原文:https://www.creativebloq.com/how-to/8-state-of-the-art-css-features
学习使用最新和最棒的CSS属性来构建和设计面向未来的网站。
CSS一直在不断地发展,规范中添加的许多功能,使得它成为web设计者手中一个强大的武器。
CSS的Grid将布局提升到了一个前所未有的高度,自定义属性引入了变量的概念,功能查询检测浏览器是否支持。媒体查询因为新的访问属性也提升到了一个新的高度。可变字体使得能用很少的代码提供去最大的创造力,滚动捕捉(scroll snapping)消除了对JavaScript的依赖。查看我们炫酷的CSS动画示例(https://www.creativebloq.com/inspiration/css-animation-examples),去看看你到底能创造出什么。或者,尝试用网站构造器(https://www.creativebloq.com/web-design/best-website-builder-8133804)构造一个网站(不需要写代码)。
对于那些有创造力的人来说,这里有用于独特布局的CSS形状,以及大量的混合模式和滤镜,以此获得和PhotoShop类似风格的设计效果。继续阅读,了解如何在最新的版本中使用这些必须尝试的新功能。但请记得,一个复杂的站点意味着你需要一个能够支持你需求的虚拟主机服务。
如果你已经使用像Sass这样的预处理器,或者确实使用过像JavaScript这样的编程语言。那么您肯定对变量这样的概念不会陌生 -- 为在代码中重用而定义的值。自定义属性使我们在css中,不需要预处理器,也能这么做。变量可以在 :root 级别设置(创建全局变量)或者在选择器作用域中设置。然后可以使用var(变量名)这样的语法来调用。例如像下面这样我们设置一个--primaryColor这样的变量:
/* On the root element (a global variable) */:root { --primaryColor: #f45942;}/* Scoped to a selector */.my-component { --primaryColor: #4171f4;}
然后我们能够使用这个变量作为属性的值:
h1 { color: var(--primaryColor);}
自定义属性是继承的,使得它产生了一些非常有用的结果。其中之一就是网站的主题化。继续上面的例子:我们能够在根结点上对--primaryColor定义一个全局的值(#f45942 -- 一个明亮的橘红色),因此每一个我们使用这个变量的地方的值将会是橘红色。但是我们可以在一个选择器内,用一个不同的值(#4171f4 -- 中蓝色)重新定义这个变量。因此在选择器内每一个使用--primaryColor变量的地方,它的计算值都会是蓝色的。
>> 设置默认值
变量作用域是个很好的特性,但有时也可能会让您很惊讶。如果你尝试使用一个还未定义的变量,这个变量的值将会回退到浏览器的默认值或者是一个继承值。而不是在级联中进一步定义的值。在某些情况下,设置一个默认值是合适的:
h1 { color: var(---primaryColor, blue);}
>> 自定义属性和预处理器的变量有何不同?
自定义属性在几个关键地方与预处理器的变量不同。在你的代码送到浏览器前,预处理器变量会先编译。浏览器从来都不知道这个值是一个变量,它只能看到最终的结果。自定义属性的值是在浏览器里被计算的。你可以在现代的开发者工具中检查它们,改变变量并且查看解析的结果。它们是动态的变量,意味着它们的值可以在css中被改变,或者在JavaScript运行时中被改变。
不像预处理器的变量,自定义属性不能被用在选择器的名字中,属性名或者媒体查询声明中 --- 它们只能被用作CSS属性的值。css预处理器仍然有很多好处,因此我们可能会看到它们还会继续存在一段时间,但是它们可能更多的是和自定义属性组合起来一起被使用。
功能查询是一种测试一个浏览器是否支持css文件中某个特定的CSS属性-值组合的方式。它们实际上消除了对像Modernizr这种功能检测库的需求。它的语法和媒体查询很像:使用 @supports 关键字,跟上你的 属性-值 对。如果浏览器满足这个特殊的条件,它就会执行那些被包裹其中的代码。
功能查询在现代浏览器中得到了很好的支持。但是它们相对来说都是比较新的浏览器,然后另外一个问题可能就是,某个你想要测试是否支持某个属性的浏览器,可能本身并不支持功能查询。通常,处理这种问题最好的方式,就是提供一个后备样式(在功能查询之外),然后在 @suports 规则中包裹浏览器支持的增强特性。
要特别注意,功能查询需要谨慎使用。CSS中最伟大的功能之一就是浏览器会简单地忽略任何它们不理解的属性和值。只有在不这么做会产生视觉bug的情况下,才去使用功能查询,否则你将会为自己增加许多额外的工作。
怎么样去使用功能查询
为了测试单个属性值的支持,我们可以先提供一个后备样式。在下面这个示例中,我们为不支持网格布局的浏览器提供了一个 flexbox 的后备样式。
.my-component { display: flex;}@supports (display: grid) { .my-component { display: grid; }}// 或者.my-component { display: grid;}@supports not (display: grid) { .my-component { display: flex; }}
您可能已经习惯使用媒体查询去探测视口的宽度和高度,以及媒体的类型(通常是screen和打印)。Level 5的媒体查询规范为我们带来了一些可选的需要测试的新媒体特性,它们已经在某些浏览器中得到了支持。这些都给可访问性提供了很好的帮助。
患有前庭疾病的用户以及患有晕车病的用户可能不会喜欢有很多动作移动的页面,例如动画和视差滚动效果。通过使用prefers-reduced-motion媒体查询,我们能给用户提供一个减少动画的选择。
.my-element { animation: shake 500ms ease-in-out 5;}@media (prefers-reduced-motion: reduce) { .my-element { animation: none; }}
网站提供一个可选的深色主题已经变得越来越流行。Prefers-colors-scheme能够帮住我们查询用户是否设置了一个系统范围的颜色喜好(使用关键字dark、light或者 no-preference),并相应地显示适当的配色。
/* Media queries 02 */body { background: linear-gradient(to bottom, #b5faff, #ffe2b4);}@media (prefers-color-scheme: dark) { body { color: white; background: linear-gradient(to bottom, #0c1338, #3e3599); }}
通常,如果我们希望在我们的网页上包含同一家族的一系列不同字体,我们一般也需要加载相同数量的字体文件。加载的字体文件越多,你的网页也就越重。从而影响性能 -- 因此通常明智的做法就是最多加载三到四个字体文件(取决于你的性能期望)。
可变字体会改变所有的这些问题。它使得我们只需要一个字体文件就能加载整个字体家族。尽管这个文件通常比单个字体文件会大一点点,但是如果你想使用不同的粗细和风格,可变字体是一个更加性能的解决方案。如果您已经购买了整个字体加载,请记住将其安全的存储在云存储中,避免丢失文件。
>> 变化轴
不仅仅如此,而且使用可变字体,我们也不仅限于一小部分的字体粗细。使用常规字体时,我们可用的字体粗细通常都是用100的倍数描述。通常,400表示常规粗细,300表示细体,700表示粗体-不同的字体家族支持不同的粗细。可变字体有一个可变的轴,对于某些属性,它给我们提供一个范围内的值,例如字体粗细。字体的变化轴可能为1-900,这将会使得我们能够使用900种不同的字体粗细。
这个变化的轴不仅仅局限于字体粗细。可变字体可以有x高度、倾斜、衬线长度、对比度(仅仅举几个例子)等不同的变化轴,这意味着单个字体文件可以为我们提供数百种甚至数千种变体。我们甚至可以给这些属性设置动画,从而使我们获得一些非常酷的效果。Mandy Michael(https://codepen.io/mandymichael)拥有大量的能够真实的测试这些极限的创意示例。
浏览器对可变字体的支持非常好。并且许多字体生产商都非常积极地开发新的可变字体,让你现在就可以立即使用。尽管它们经常都是专业版,特别是那些有着更多特性的字体家族。如果你仅仅只是想试试可变字体,看看它们到底能做什么。这里存在着许多的可变字体试玩网站。
注意,如果你想立即使用可变字体,那么你需要确保你的操作系统是最新的。它们不能在老的系统上工作。
>> 字体变化的设置(font-variation-settings)
当我们想改变字体粗细的时候,我们只需要简单地使用CSS的font-weight属性。font-variation-settings是一个新的属性,它能够让我们完全的访问一个字体的不同变化轴。它们既包含预先注册的轴,也包含自定义的轴。
>>> 预先定义的轴
有五种不同的预定义轴,分别对应着CSS中的不同属性。其中每一个都有一个所谓的“轴标签”。 这些预先定义的轴分别是: wght (font-weight), wdth (font-stretch), slnt (font-style: oblique/angle), ital(font-style: italic), opsz (font-optical-sizing)。我们可以通过单个css属性或者通过font-variation-settings属性访问这些轴。
这些轴不是必须都包含在可变字体中(其中一些可能只有一个或两个变化轴),但他们可能会变得更加通用。
>>> 自定义轴
自定义轴是字体设计者包含的定制轴,可以是任何东西。它们可以包括(举例)衬线长度(serif length)、x高度(x-height),甚至其他一些更有创意的东西(排版不是那么典型),例如旋转。
这两种不同的轴,都必须表示为四个字符的标记。预定义的轴必须是大写的,而自定义的轴必须是小写的。这两者都可以在Font-Variation-Settings属性中组合使用。Font-Variation-Settings设置是可动画的,可以实现一些非常酷的UI效果!其中在图标字体中也进行了一些非常有趣的实验。
假如你对像Photoshop和Illustrator这类的设计工具熟悉,那么你可能会注意到混合模式(blend modes)和它们怎么被用来在图片上制作不同的效果。混合模式的工作方式是使用数学公式将两个或者多个层混合在一起,以计算每个像素的结果值。图层可以是任何东西--图片、渐变或者纯色。其中有些混合模式会产生比较黑的结果(例如,乘,将图层的像素值相乘),也有比较亮的(例如,遮盖和覆盖)。然而,我们不需要理解它们的数学原理就能使用它们。尝试使用不同的混合模式可以给我们一个很好的感觉,当与不同的层组合时,哪种混合模式会产生想要的效果。
通过CSS属性mix-blend-mode和background-blend-mode,我们能够在浏览器里获得像Photoshop这样的图片效果。这两个属性都使用相同的属性值,但工作方式稍微有些不同。
>> Background-blend-mode
背景混合模式将目标的背景层混合在一起。我们的元素有背景图片、颜色和渐变。它们可以在不影响前景内容的情况下相互混合。我们可以为background-blend-mode指定多个值,每个背景层都单独指定一个。
.my-element { background: url(#myUrl), linear-gradient(45deg, rgba(65, 68, 244, 1), rgba(203, 66, 244, 0.5)), rgba(244, 65, 106, 1); background-size: cover; background-blend-mode: screen, multiply;}
>> Mix-blend-mode
Mix-blend-mode 影响这个元素怎么和它的父节点以及兄弟节点的混合,包含任何的前景和背景内容,以及伪元素。可以通过混合覆盖伪元素(::before、::after)来实现一些有趣的创造性效果。
.my-element { background: rgb(244, 65, 106); mix-blend-mode: multiply;}
>> CSS filters
CSS filter属性也被用来创造醒目的视觉效果,使用filter属性和滤镜函数值。不像混合模式,它们直接应用一个图片效果在它们指定的元素上,并且一个元素可以使用多个滤镜。
>> 改变灰度
相比依赖混合模式,我们可以更大程度上控制元素的颜色。滤镜可以把一个图片变成黑白的,可以调整明亮、对比度和饱和度,模糊一个元素或者增加一个投影。它们同样支持动画,和hover配合可以有更好的效果。
>> SVG滤镜(filters)
css滤镜实际上是一个SVG滤镜的简化版本。CSS filter 属性也接收一个url()函数,允许我们传递一个指向SVG滤镜的URL。SVG过滤器非常强大,可以实现一些令人难以置信的图片效果,但是它们也比CSS过滤器函数要复杂得多。Sara Soueidan在Codrops上有一系列文章,如果你有兴趣编写自己的自定义SVG过滤器。请在(https://tympanus.net/codrops/2019/01/15/svg-filters-101/)上阅读这些文章。
>> 裁剪(clipping)和蒙版(masking):超越矩形
我们在web上习惯于处理盒子,但是不是所有的东西都必须是矩形。裁剪和遮罩是同一个硬币的两面,是两种不同的方式,显示或者隐藏一个元素的不同部分,使得背景可一穿透显示。这使我们有能力在我们的设计中引入有趣和有创意的形状。
>>> Clip-path
这个clip-path()属性允许我们通过定义一个路径来裁剪元素。它使用一些基本的形状函数,inset(), circle(), ellipse(), 或者 polygon()。它允许我们使用一对xy坐标来定义路径,来制作更加复杂的裁剪形状。另外,我们也可以通过给path()函数传递一个SVG路径,或者使用url()函数来提供一个SVG的路径id。
>>> 不在path范围内的
裁剪一个元素,会把你定义的path之外的任何东西都裁剪掉,不过元素依旧是一个矩形。如果你有在path边界之外的内容,那么也会被一起裁剪掉--它不会包裹在形状内。
>>> Mask-image
mask-image允许我们能够通过使用一张图片(SVG或者透明的PNG)或者渐变作为蒙版来显示或者隐藏图像的某些部分。不像clip-path,我们可以使用蒙版给我们的图像添加纹理,因为蒙版源不是一个路径,它允许是透明的。
CSS Shapes规范允许我们将文本环绕在浮动的几何形状周围,创造有趣的,像杂志一样的布局。使用shape-outside属性能够做到这一点。和clip-path类似,我们可以给这个属性一个基本的形状函数,circle(), ellipse(), inset(), polygon(), 或者一个指向SVG的path,事实上,这两个一起工作的非常协调。shape-outside可以有效地包裹我们的文本,但不会影响浮动元素。如果我们想要我们的文本看起来像环绕在一个图片或者浮动元素周围,我们也能够使用和clip-path相同的值。使用 shape-margin 增加形状路径和包裹它内容之间的空白。可以看一下Stuff & Nonsense(https://stuffandnonsense.co.uk)的网站,看看css-shape是怎么被用来把文字包裹环绕一个位于中心的图片。
FireFox 在开发者工具栏面板里有一个 shape-path 编辑器,这个对于复杂的形状工作来说非常有用。 但是,也必须小心使用。包裹一段文字的开头有着非常好的艺术效果,但是却不一定有最好的用户体验。复杂的锯齿形状会使那一块的文本非常难以阅读。对于重要的文本,你依然想让它清晰明了。
许多网站利用JavaScript库的优势去提供一个流畅的、像本地App那样的滚动体验,当用户滑动页面的时候,内容快速定位到指定的位置。现在,随着滚动捕获的规范被制定,我们能够在我们的CSS文件中完成这个操作--这就不需要引入大量的JS模块,使得页面变得很重。
为了实现滚动捕获,我们需要一个元素去作为我们的滚动容器。容器的直接子元素指示将要捕捉地点,并且可以在捕捉区域以各种不同的方式对齐。
当我们和另一个新的CSS属性值--position: sticky组合使用时,滚动捕捉能够会更有效果。这个position的值表示,当子元素在容器内部滚动的时候,它会“粘住”在一个指定的位置--这是另外一个,以前只能用javascript实现的功能。点击可以查看这个滚动捕捉和位置结合的示例。sticky and intersectionObserver示例(https://www.creativebloq.com/inspiration/css-animation-examples)。
前端开发人员使用当时可用的任何工具来突破布局的局限---最新的flexbox,这是大多网格系统使用的工具。但是flexbox就不是严格得为网格布局所设计的,它的目的是弹性布局。
CSS Grid是第一个为二维布局设计的规范,可以让我们能够完全的,在行和列上,同时控制构建布局和放置元素。用Grid构造一个响应式布局不需要calc()或者用负margin来hack。这个秘密武器就是fr单位---一个新的,唯一Grid布局能使用的单位。这个fr单位按比例分配网格轨道(行和列)的可用空间。它考虑了所有的固定轨道、空隙和内容,然后相应地分配剩余空间。Jen Simmons创造了“真正的web设计”这一词,来描述Grid使用者所在的web新时代。
>> 怎么使用CSS Grid
Grid需要一个"display"属性设为“grid”的元素,来作为一个网格容器。网格容器的直接子元素都是能够被放置在grid网格轨道的项目。我们使用grid-template-rows 和 grid-template-columns属性去定义网格轨道(行和列),使用 column-gap 和 row-gap 去定义空隙(轨道间距)。
.grid { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 200px); gap: 20px;}
我们使用repeat()函数,使得代码更加简洁,用来作为纯手写的替代(例如 grid-template-columns: 1fr 1fr 1fr 1fr)。这个也是对 row-gap 和 column-gap使用简写gap。
上面的代码给了我们一个四行轨道,每个高200px,并且四个列轨道,通过使用fr单位,每个列轨道等分全部可用的空间。
值得注意的是,这并不是创建网格布局的唯一方式。通过放置网格项目可以创建隐式的轨道。如果您使用grid布局,对此了解是很有用的。只有更加深入地理解网格布局在不同条件下的行为,才能使得布局的代码更加简洁。
我们可以通过引用网格线编号来放置元素,网格线是位于每个轨道之间的数字线。我们使用简写 grid-column 和 grid-row 来代替 grid-column-start, grid-column-end, grid-row-start 和 grid-row-end。这是告诉浏览器,我们的项目在每一个轴上开始的数字线和结束的数字线。
.item { grid-column: 1 / 4; grid-row: 2;}
Grid给我们提供了许多放置元素的方式:我们能够使用名字代替网格线。
.grid { display: grid; grid-template-columns: [image-start] 1fr 1fr 1fr [image-start] 1fr; grid-template-rows: 200px [image-start] 200px 200px [image-end] 200px; gap: 20px;}
或者通过使用grid-template-area属性来让我们用文字去画出一个布局
.grid { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(4, 200px); gap: 20px; grid-template-areas: ‘. . . .’ ‘image image image .’ ‘image image image .’ ‘. . . .’;}
使用这两者中的任意一个方法,我们可以在放置网格项目时简单引用相应的网格区域。
.image { grid-area: image;}
这篇文章原始发布在creative web design magazine(https://www.creativebloq.com/web-designer-magazine)。