上一期咱们围绕着Web动画展开,其中有的动画对部分用户群体会造成不良的反应,会引起癫痫。为此,为了避免这种现象出现,可以使用条件CSS@media中的prefers-reduced-motion条件来做处理。除此之外,prefers-reduced-motion<picture>元素中还有一些小技巧,可以帮我们做一些其他有意义的事情。这一期,就从这个特性开始讲起。

prefers-reduced-motion<picture>的结合

如果你对Web中图像相关的知识感兴趣的话,可以花点时间阅读下面相关的文章:

回到prefers-reduced-motion<picture>上来。

当用户系统中开启减弱动态效果之后,我们就可以通过媒体查询@mediaprefers-reduced-motion来减弱动态效果,即元素直接不启用任何动效

/* 开启 减弱动态效果 的设备会禁用 aniName动画 */ 
@media screen and (prefers-reduced-motion) {
/ * 禁用不必要的动画 * /
.element {
animation: none;
}
}

上面对于CSS控制的动效可以得到很好的降级处理,但Web页面会启用一些.gif动态图片。那么对于使用媒体查询就不好处理。不过,值得庆幸的是,HTML5的<picture>可以基于source中的media值来对动态图做一些降级处理。当然,在media中也同样需要基于prefers-reduced-motion的取值。比如下面这个示例:

<picture>
<source srcset="static.png" media="(prefers-reduced-motion: reduce)" />
<img srcset="animated.gif" alt="animated image" />
</picture>

就上面的示例而言,在<picture>中的<img>元素引入了默认的动态图片,然后在<source>中引入降级处理的图片。一旦用户系统启用了“减弱动态效果”:

Web终端(比如Safari浏览器)就会启用降级图片static.png

虽然.gif动图可以让视觉效果动起来(Web动效中模式之一),但.gif文件的引用在性能上是有所制约,特别是在移动终端上。不过,除了.gif动图之外,还可以使用.mp4这样的视频文件也能让Web视觉效果动起来,而且视频要比.gif图性能好得多。事实上,有不少同学开始.gif文件转换成视频文件,然后再将其运用到Web中。

那么我们就可以在<picture><source>中引入一个.mp4文件。只不过这样我们就需要三个源媒体文件:

  • 当开启“减弱动态效果”,会启用非动态图片,比如static.png
  • 同样在<img>中引用一个动态图片做为默认资源,比如animated.gif
  • 如果识别<picture>中引用的资源,而且未开启“减弱动态效果”,则会启用视频文件来替代.gif图,比如animated.mp4

例如:

<picture>
<source srcset="static.png" media="(prefers-reduced-motion: reduce)" />
<source srcset="animated.mp4" type="video/mp4" />
<img srcset="animated.gif" alt="animated image" />
</picture>

就上例,在不同的浏览器会加载不同的源媒体:

虽然Firefox也支持<picture>元素,但它似乎不能正常工作,加载的依旧是animated.gif文件。具体原因不名,有可能是Firefox对<source>的支持还有一定的缺陷。

有关于这方面更详细的介绍可以阅读@Chris Coyier的《Reduced Motion Picture Technique, Take Two》一文。

Flexbox 和 Grid 容器中的伪元素

在Flex容器或Grid容器上可以使用伪元素::before::after。运用于容器的伪元素在很大程度上就像一个子元素,因此也自动会变成Flex项目或Grid项目。

https://codepen.io/airen/pen/QebxOM

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-sizeline-height相关的设计(有关于文字排版);另一部分就是有关于间距的设计。

响应式排版

: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-ratio1em不是基于--text-base-size的值。你可以根据自己的需要设置--text-base-size的值不等于1em。由于em单位是基于当前font-size的大小计算的,如果我们在不同的媒体查询中更新--text-base-size的值,那么就会更新bodyfont-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()

其中有关于map()filter()reduce()的几个方法,有很多非常形象的图来阐述,比如@Una Kravets的手绘图

@JavaScript Teacher还为这几个API设计了相应的动态图

有关于这方面更多的介绍,可以阅读:

小结

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
原文: https://www.w3cplus.com/web/web-tips-15.html © w3cplus.com

“大漠”,w3cplus.com 创始人。前端码畜,专业搬运工

“大漠”,w3cplus.com 创始人。前端码畜,专业搬运工