Web技巧(15)
上一期咱们围绕着Web动画展开,其中有的动画对部分用户群体会造成不良的反应,会引起 癫痫 。为此,为了避免这种现象出现,可以使用条件CSS中 @media
中的 prefers-reduced-motion
条件来做处理。除此之外, prefers-reduced-motion
在 元素中还有一些小技巧,可以帮我们做一些其他有意义的事情。这一期,就从这个特性开始讲起。
prefers-reduced-motion
和
的结合
是HTML5的一个元素 ,可以使用该元素来较好的实现响应式图片。另外,HTML的
元素的
srcset
和 sizes
属性也能实现类似的效果。
如果你对Web中图像相关的知识感兴趣的话,可以花点时间阅读下面相关的文章:
回到 prefers-reduced-motion
和 上来。
当用户系统中开启 减弱动态效果 之后,我们就可以通过媒体查询 @media
中 prefers-reduced-motion
来减弱动态效果,即 元素直接不启用任何动效 :
/* 开启 减弱动态效果 的设备会禁用 aniName动画 */ @media screen and (prefers-reduced-motion) { / * 禁用不必要的动画 * / .element { animation: none; } }
上面对于CSS控制的动效可以得到很好的降级处理,但Web页面会启用一些 .gif
动态图片。那么对于使用媒体查询就不好处理。不过,值得庆幸的是,HTML5的 可以基于
source
中的 media
值来对动态图做一些降级处理。当然,在 media
中也同样需要基于 prefers-reduced-motion
的取值。比如下面这个示例:
就上面的示例而言,在 中的
元素引入了默认的动态图片,然后在
中引入降级处理的图片。一旦用户系统启用了“减弱动态效果”:
Web终端(比如Safari浏览器)就会启用降级图片 static.png
。
虽然 .gif
动图可以让视觉效果动起来(Web动效中模式之一),但 .gif
文件的引用在性能上是有所制约,特别是在移动终端上。不过,除了 .gif
动图之外,还可以使用 .mp4
这样的视频文件也能让Web视觉效果动起来,而且视频要比 .gif
图性能好得多。事实上,有不少同学开始 将 .gif
文件转换成视频文件 ,然后再将其运用到Web中。
那么我们就可以在 的
中引入一个
.mp4
文件。只不过这样我们就需要三个源媒体文件:
- 当开启“减弱动态效果”,会启用非动态图片,比如
static.png
- 同样在
中引用一个动态图片做为默认资源,比如
animated.gif
- 如果识别
中引用的资源,而且未开启“减弱动态效果”,则会启用视频文件来替代
.gif
图,比如animated.mp4
例如:
就上例,在不同的浏览器会加载不同的源媒体:
虽然Firefox也支持 元素,但它似乎不能正常工作,加载的依旧是
animated.gif
文件。具体原因不名,有可能是Firefox对 的支持还有一定的缺陷。
有关于这方面更详细的介绍可以阅读@Chris Coyier的《 Reduced Motion Picture Technique, Take Two 》一文。
Flexbox 和 Grid 容器中的伪元素
熟悉 Flexbox 和Grid布局的同学都应该知道。 如果在元素上显式的设置 display
的值为 flex/inline-flex
或 grid/inline-grid
就会创建Flex容器或Grid容器,同时就创建了FFC(Flexbox Formatting Context)或GFC(Grid Formatting Context) 。那么Flex容器或Grid容器的子元素就自动成为 Flex项目或Grid项目 。同时相应的Flex项目属性或Grid项目属性就可以运用到这些元素之上。
在Flex容器或Grid容器上可以使用伪元素 ::before
或 ::after
。运用于容器的伪元素在很大程度上就像一个子元素,因此也自动会变成Flex项目或Grid项目。
Flex容器或Grid容器中的伪元素 ::before
或 ::after
看上去像一个子元素。不过有一个棘手的问题,除了用于创建它的选择器之外,没有其他选择器可以选中它。
ul::before { content: 'x'; display: inline-flex; justify-content: center; align-items: center; min-height: 10vh; background: #f36; margin: 5px; color: #fff; }
或许你会想到,既然伪元素看上去像一个子元素,那么结构性选择器,比如 :nth-child()
或 :nth-last-child()
可以选中。事实是不可以的,如果伪元素和子元素完全一样,将会影响这些选择器。
ul > :nth-child(1) { background: #f90; border:2px solid #09f; } ul > :nth-last-child(2) { background: #09f; border:2px solid #f90; }
另外一个问题就是,在JavaScript中不能像选择常规子元素那样选择伪元素。比如, document.querySelector('.flex::before')
将返回一个 null
。如果你想在JavaScript选中伪元素以及想看看它的样式规则,可以使用CSSOM中的相关特性来获取到:
const styles = window.getComputedStyle( document.querySelector('.flex'), '::before' ) console.log(styles.content) // ❯ "x" console.log(styles.color) // ❯ rgb(255, 255, 255) console.log(styles.getPropertyValue('color')) // ❯ rgb(255, 255, 255)
基于CSS自定义属性和 em
单位的吶应式布局
响应式布局中会根据不同的终端屏幕设计不同的字号、间距等。在以前的相关教程介绍了精准流体布局的方法:
其实他们的原理非常简单,利用 视窗单位 vw
等和 calc()
函数 来计算 font-size
或者 padding
等属性的值。
@guerriero_se在的新博文 中介绍了另一种实现响应式布局的方法,即 基于 CSS自定义属性 和 em
单位 。
主要分为两部分,一部分是对 font-size
、 line-height
相关的设计(有关于文字排版);另一部分就是有关于间距的设计。
响应式排版
为了控制文本相关的缩放,定义了两个自定义属性: --text-base-size
和 --text-scale-ratio
。第一个是 body
元素的 font-size
;第二个是用于缩放的比例。而且 --text-base-size
的默认值是 1em
。
:root { // body font size --text-base-size: 1em; // type scale --text-scale-ratio: 1.2; --text-xs: calc((1em / var(--text-scale-ratio)) / var(--text-scale-ratio)); --text-sm: calc(var(--text-xs) * var(--text-scale-ratio)); --text-md: calc(var(--text-sm) * var(--text-scale-ratio) * var(--text-scale-ratio)); --text-lg: calc(var(--text-md) * var(--text-scale-ratio)); --text-xl: calc(var(--text-lg) * var(--text-scale-ratio)); --text-xxl: calc(var(--text-xl) * var(--text-scale-ratio)); --text-xxxl: calc(var(--text-xxl) * var(--text-scale-ratio)); // line-height --body-line-height: 1.4; --heading-line-height: 1.2; // capital letters - used in combo with the lhCrop mixin --font-primary-capital-letter: 1; }
注意,在定义每种文本大小类型的自定义属性时,使用 1em
乘以 --text-scale-ratio
。 1em
不是基于 --text-base-size
的值。你可以根据自己的需要设置 --text-base-size
的值不等于 1em
。由于 em
单位是基于当前 font-size
的大小计算的,如果我们在不同的媒体查询中更新 --text-base-size
的值,那么就会更新 body
的 font-size
,并使用级联效应,更新所有文本大小自定义属性。这样一来,整个排版都会受到影响。
@supports(--css: variables) { :root { @include breakpoint(md) { --text-base-size: 1.25em; } } }
响应式间距
响应式间距和响应式排版有点类似:
:root { --space-unit: 1em; --space-xxxxs: calc(0.125 * var(--space-unit)); --space-xxxs: calc(0.25 * var(--space-unit)); --space-xxs: calc(0.375 * var(--space-unit)); --space-xs: calc(0.5 * var(--space-unit)); --space-sm: calc(0.75 * var(--space-unit)); --space-md: calc(1.25 * var(--space-unit)); --space-lg: calc(2 * var(--space-unit)); --space-xl: calc(3.25 * var(--space-unit)); --space-xxl: calc(5.25 * var(--space-unit)); --space-xxxl: calc(8.5 * var(--space-unit)); --space-xxxxl: calc(13.75 * var(--space-unit)); }
设置了一个自定义属性 --space-unit
的值为 1em
,而且模块化缩放比例是基于斐波那契数列(Fibonacci sequence)。同样的,在不同的媒体查询中, --space-unit
可以设置不同的的值:
@supports(--css: variables) { :root { @include breakpoint(md) { --space-unit: 1.25em; } } }
有关于更详细的代码,可以查阅读 CodyHouse Framework 。
图解JavaScript的 map()
、 filter()
和 reduce()
JavaScript中有关于数组的API有很多:
其中有关于 map()
、 filter()
和 reduce()
的几个方法,有很多非常形象的图来阐述,比如 @Una Kravets的手绘图 :
@JavaScript Teacher还为这几个API设计了相应的动态图 :
有关于这方面更多的介绍,可以阅读:
- Map, Filter and Reduce – Animated
- An Illustrated (and Musical) Guide to Map, Reduce, and Filter Array Methods
- JavaScript’s Reduce Method Explained By Going On a Diet
- JavaScript Map() Method Explained by Going On a Hike
- JavaScript’s Filter Function Explained By Applying To College
小结
在这一期中主要围绕三个部分展开,其一介绍了 prefers-reduced-motion
媒体查询条件和HTML5的 的
结合在一起对动态图片做降级处理,或者说在最适合的环境加载最适合的源媒体;其二介绍了如何使用CSS自定义属性和
em
单位实现响应式布局的另一种方法;其三介绍了Flexbox和Grid容器中的伪元素会生成相对应的项目,具备Flex项目、Grid项目的属性,不过他们看上去类似子元素,但结构性选择器无法运用到其身上,如果使用JavaScript来操作伪元素的样式的话,需要借助CSSOM等特性。最后用收集了不同的图来阐述JavaScript的 map
、 filter
和 reduce
等API特性。