计划组件的响应行为可能会很棘手,尤其是当组件布局受其内容高度影响时。
例如,让我们考虑一个表组件。您可能决定使用两种不同的布局:一种针对较小的屏幕(状态a布局)进行了优化,另一种针对较大的屏幕(状态b布局)进行了优化。
然后,您需要确定布局更改的断点,并使用媒体查询在CSS中进行设置。
但是,同一表组件可以具有两列或二十列。
如果表的列数较少,则可以决定在较小的断点处更改布局:
相反,对于具有更多列或更丰富内容的表,您可能需要稍后对其进行更改,以确保在小屏幕上看起来不会过于拥挤:
理想情况下,您应该找到一个对它们都适用的断点(以及您网站上的所有其他表)。您可以使用一个.table
类来定义状态a布局的样式,并使用媒体查询覆盖状态b布局的样式:
<table class="table">
<!-- table content -->
</table>
<style>
.table {
/* state-a layout style */
@media (min-width: 600px) {
/* state-b layout style */
}
}
</style>
该解决方案可能不是理想的选择,因为您选择的断点是一个折衷方案:您最终可能会发现某些表看起来过于拥挤而另一些表却过于稀疏。即使您找到了适用于今天的表的解决方案,也很可能会与明天的表一起打破。
类修饰符
一种可能的选择是定义响应式类修饰符(共享相同样式但针对不同断点的类),以选择在不同断点处触发布局更改。
如果我们考虑一个带有两个断点(中小)的示例,您将拥有:
.table {
/* state-a layout style */
}
/* small breakpoint */
@media (min-width: 600px) {
.table--state-b\@sm {
/* state-b layout style */
}
}
/* medium breakpoint */
@media (min-width: 1000px) {
.table--state-b\@md {
/* state-b layout style */
}
}
然后您可以<table>
根据其内容将这些修饰符应用于不同的:
<!-- 👇 switch layout at a small breakpoint -->
<table class="table table--state-b@sm"></table>
<!-- 👇 switch layout at a medium breakpoint -->
<table class="table table--state-b@md"></table>
.table--state-b@sm
该类中定义的代码与中的代码相同.table--state-b@md
。请记住,这两个类用于创建相同的布局。它仅适用于不同的断点。
这种方法有两个主要缺点。第一个是代码的可维护性:如果您需要更改state-b布局,则需要更新两个不同的类(.table--state-b@sm
和.table--state-b@md
)。您可以使用CSS预处理器(例如,使用SASS mixins)解决此问题。
第二个问题是在最终CSS中将state-b的CSS代码重复多次(如果有两个修饰符,则重复两次,但是如果需要其他变体,则可能更多!)。
对所有组件和不同的媒体查询重复此操作,这可能会导致CSS文件大小显着增加。
解
在研究CodyHouse组件库的表类别时,我们最终使用了一种不同的方法。我们为state-b布局定义了一个类:
.table {
/* state-a layout style */
}
.table--state-b {
/* state-b layout style */
}
然后,我们--table-layout
在.table
类内部定义了CSS自定义属性,并使用类修饰符修改了其值:
.table {
--table-layout: state-a;
}
@media (min-width: 600px) {
.table--state-b\@sm {
--table-layout: state-b;
}
}
@media (min-width: 1000px) {
.table--state-b\@md {
--table-layout: state-b;
}
}
注意,现在使用类修饰符来更改CSS自定义属性的值。没有重复的版式风格。
使用JavaScript,我们可以.table--state-b
根据此CSS自定义属性的值检查是否添加或删除类。这将应用适当的布局样式!
var layout = getComputedStyle(table).getPropertyValue('--table-layout');
table.classList.toggle('table--state-b', layout == 'state-b');
这种技术使我们可以使用单个类(.table--state-b
)作为布局样式,而不考虑媒体查询。添加新版本仅需要设置单个CSS自定义属性的值。不涉及代码重复!
在此示例中,我们一直在处理表,但是您可以将此技术应用于响应能力受其内容高度影响的任何组件。
缺点?
这种方法需要JavaScript才能起作用,但这不应该成为问题:如果JS已关闭,我们将提供状态表的状态版本,该版本可以完全访问。
CSS自定义属性支持如何?使用CSS变量可能是最干净,最容易解释的方法。但是,如果您需要支持较旧的浏览器(例如IE 11及更低版本),则可以使用::before
伪元素并使用类修饰符更改其内容:
.table::before {
display: none;
content: 'state-a';
}
@media (min-width: 600px) {
.table--state-b\@sm::before {
content: 'state-b';
}
}
@media (min-width: 1000px) {
.table--state-b\@md::before {
content: 'state-b';
}
}
在JS中,您可以检查::before
内容的值,而不是自定义属性。结果相同,不同的浏览器支持!您可以根据需要决定。