得益于媒体查询,我们可以让自己的网站在任何设备上都能获得很好地视觉效果。但是如果不用媒体查询呢?其实有很多技术也能帮助我们实现响应式布局,并且它们比使用媒体查询更加系统化、规范化。
如果你和我一样比较懒的话,你可能会对布局系统感兴趣。这种可以自适应的布局系统可以根据我们的设置来自动调整页面布局,非常方便。
我们一直希望可以创建一个灵活的布局系统。在过去我们用float等基础CSS属性就可以创建一些适应于不同屏幕大小的布局。现在我们则可以用一些新的CSS特性,如flexbox和一些viewport相关的单位。它们可以帮助我们创建一个更加强大的CSS布局。
让我们从一个简单的例子开始探索布局系统吧。很多博客都会在首页上列出一些文章的简介。在一些小屏设备上你可能希望这些简介是上下排列的,而在一些宽屏设备上你希望他们可以排成多列。
如果我们将每个文章的最大宽度设为20em,并添加float:left样式,那么浏览器就会根据屏幕宽度将内容排成尽可能多的列。但是这种浮动的布局有一个问题,它不会自动清除留白,有些高度较大的子元素会将父元素撑起来,因此其高度不够的兄弟元素的下边会有部分留白。
对于这种带留白的布局人们褒贬不一,有的人觉得看起来不错,有的人则忍受不了那部分留白。如果你不想让这些留白的部分空着,你可以使用display:inlineblock;。
Float是一个非常原始的创建响应式布局系统的方法。不需要媒体查询就可以实现响应式,但是可能需要根据实际效果来调整你的布局。纯float布局可能并不适合于所有使用场景,但确实是一个值得考虑的方案。
我很奇怪为什么那么多网站没有使用CSS的列属性(column),或许是因为适配起来问题比较多吧。但是就因为这样而放弃这个灵活的布局技术实在有点可惜。对于包含链接列表(如导航、脚注、搜索结果和带照片的博客)的网页来说使用column还是很不错的。
CSS column在处理article标签的时候也很常用。如果文章内容过多,高度超出了屏幕范围,那么用户体验就会很差,用户不希望在阅读的时候还要上下滚动。使用column就可以解决这个问题。你可以设置article标签的最大高度为viewport的100%,列的最小高度为20em,从而创建出一个多列的布局。但是如果内容特别多的话,排成多列之后很可能在水平方向上会超出屏幕范围,这时候你就要考虑如何说服用户左右滚动屏幕了。
你可以添加一个新的元素来解决这个问题,或者干脆就让article标签的宽度小于viewport,像下面这样设置CSS:
- article {
- columns: 20em; /* 不小于20em */
- height: 100vh; /* 与viewport等高 */
- width: 75vw; /* 占viewport宽度的75% */
- }
特别注意:overflow属性的值要设为visible,否则这个多列布局会出问题。
Tab Atkins很好地解释了什么是flexbox:
“Flexbox是按照直线排列的布局,布局中的元素都以一条直线(或者是多条可以通过平移拼成一条直线的直线)作为基准排列。”
这听起来有点类似于float,但是flexbox要更加强大。举个例子来说,float无法处理留白的问题,而flexbox就可以。你可以通过设置一些属性来调整容器中元素的对齐方式,从而间接调整留白的位置。你可以让留白处于元素之间或者处于元素周围的位置,或者通过拉伸元素填充整个容器从而消除留白。
我通过这种方法来调整网站首页中链接的位置。我不希望它们排成一个有序地多列布局,而是希望每一行能容纳尽可能多的元素。我最初是这么设置的:
- ul {
- display: flex;
- flex - wrap: wrap;
- font - size: 2.5em;
- }
这在大屏设备上效果不错,但是在小屏上就有问题了。我希望不管容器中的元素有多大都能在屏幕中全部看到,而不是通过滚动网页才能看到全部内容。要解决这个问题,我可以使用媒体查询。但是如果浏览器可以根据viewport来自动调整字体大小的话不是更好吗?如果要实现这一点,那就需要使用viewport相关的单位了。
如果想让你的布局适应不同viewport的话,你可以用vw作为宽度单位。vw代表viewport宽度的百分比,如果你将字体大小设为2.9vw你的布局会自适应viewport,如下图所示:
但是这么设置会遇到一个问题:在特别小的屏幕上,字体会特别小甚至看不清楚,而且vw作为单位的元素无法通过浏览器的放大功能放大。
为了解决这个问题,你可以使用calc方法设置font-size为calc(1em+1vw)。这样可以设置字体的最小值。但是将链接全部显示在任意大小的屏幕上这一问题还没有解决。
使用纯CSS来完美适应任意一个屏幕是不太可能的,但是我们可以尽量做到自适应的效果。CodePen上有Dillon de Voor分享的一段代码:
- font - size: calc(4vw + 4vh + 2vmin);
这个表达式可以将字体调整到合适的大小,在任一个屏幕上都能显示全部内容,如下图所示。
在我的网站里我根据网站的实际情况调整了一下表达式的值,满足了我的要求:内容会尽量充满整个屏幕,如下图所示:
当然这不可能一直有效。通常你需要针对一些特殊情况进行特殊处理,比如针对一些极端的屏幕大小你就需要额外处理,这时候你还是要用到媒体查询,而且写起来非常方便。
当我们用久了媒体查询来创建响应式布局之后,便会发现它的局限性。我相信你有时候会需要所谓“元素查询(element query)”的功能:以元素的大小为依据来改变它们的外观,而不是依据屏幕的大小。有时候实现这一点能解决很多问题。
然而现实当中并没有“元素查询”,因为它会造成一个“鸡生蛋蛋生鸡”的问题。你如何将一个比30em宽的元素的宽度设为20em呢?响应式问题社区组织(Responsive Issues Community Group)提出了一个未来可能的解决方案:我们不能使用元素查询,但我们可以用容器查询(container query)。容器查询不是给容器本身添加样式,而是容器中的元素。容器查询可能会像下面写的这个样子:
- article:media( min-width: 30em ) screen {
- …
- }
这个假想的写法将来可能会发生改变,但是基本的实现思路是不变的。
除了屏幕大小以外还有其他设定样式的依据。最近有很多精彩的文章都讨论了基于量的样式这一新方法。
基于量的样式可以使你根据某个元素的兄弟元素的个数来添加样式。这项技术不利用媒体查询和所谓“容器查询”并且很好地应用了各种选择器。
利用量选择器你可以实现很多功能。你不需要知道量选择器过滤出的元素有多少个,量选择器可以根据你设置的条件(如搜索结果的个数)给满足条件的元素添加样式。上图便是我利用量选择器添加样式之后的结果,筛选出了苏黎世前端大会上发言人的照片。
上面的这个示例可以在这里看到效果。一开始,用户可以看到所有的发言人和主持人。每张图片都比较小,正好可以放进屏幕里。但是经过筛选只剩下主持人时,如果图片还保持原来的大小,那么留白就太多了。这个强大的技术可以调整图片大小以清除留白,让屏幕中正好放进两张图片。
下面这段代码的选择器实现了上述效果。它看上去可能有些复杂,但是当你理解了它的用法之后就会感受到它的奇妙之处。
- article {
- flex - basis: 100vmax;
- }
- article: nth - last - of - type(n + 2),
- article: nth - last - of - type(n + 2)~article {
- flex - basis: 50vmax;
- }
- article: nth - last - of - type(n + 6),
- article: nth - last - of - type(n + 6)~article {
- flex - basis: 33.33vmax;
- }
这段代码告诉浏览器article标签的宽度应尽可能和viewport一样宽,但是如果有两个及以上article标签的话,那么他们会各占viewport的50%,如果有6个以上的话则会各占viewport的33.3%。
vmax不仅仅以最有效的方式填满了viewport,它还会根据viewport的比例来调整内部结构。通过这几行代码你就可以创建一个以内容和viewport为根据的自适应布局系统。
这次我们主要给大家介绍了如何让浏览器决定布局。根据需要使用尽可能多的列,不要让他们小于20em。尝试去使用一些CSS的新特性,如flexbox和viewport相关的单位,这会让你的设计更加强大、简洁。我们这次仅展现了它们的冰山一角就得到了如此棒的效果。希望这篇文章能为你抛砖引玉,帮助你开始CSS新特性的探索。
当然,这不是实现响应式布局的唯一途径。现有的其他CSS模型(如CSS栅格布局和CSS Shapes)可以帮助我们管理布局,调整内容的大小。但如果可能的话,我们可以摆脱它们的控制而是让浏览器和内容来决定布局,这样的效果会更酷一些。
via creativebloq
来源: http://igeekbar.com/igeekbar/post/100.htm