Web技巧 (03)

发布于 大漠

又到了每周CSS技巧发布的时间了,在正式发布这期之前,先说一下,从这期开始将以Web技巧的标题来发布,因为今后发布的内容不再局限于CSS的方面,或涉及到Web的其他技术或特性。原则是同样的,将会以自己在本周看到的一些有关于Web技术有意思的知识,将每个知识点整理成文来发布。在上一期中,主要围绕着CSS的border来扩展故事。那么这一期将会涉及到哪些Web知识点呢?感兴趣的同学请继续往下阅读。

断行排版:连字符hyphens的使用

在Web排版的时候,特别是英文排版时,时常会碰到断行难于处理的现象。在CSS中其实有一个属性hyphens会告诉浏览器在换行时如何使用连字符连接单词。可以完全阻止使用连字符,也可以控制浏览器什么时候使用,或者让浏览器决定什么时候使用。

连字规则具有语言特性。在HTML中,由lang属性决定,浏览器只会在当前属性存在且有合适的连字字典可用的情况使用连字符进行连接。如果在XML中,必须使用xml:lang属性。

接下来来看看怎么使用连字符hyphens属性。

自动断字需要两个步骤。首先设置文本的语言格式,这将会告诉浏览器使用哪个连字符字典,因为不同的语言断行连接都会根据对应语言提供的连字符字典来做处理。如果浏览器不知道文本的语言,即使在样式中设置了hyphens属性,也将会被视为不需要自动连字符。

前面提到过了,设置文本语言格式非常的简单,就Web而言,只需要在html标签中添加lang属性即可:

<html lang="en">

无论是否使用连字符,以这种方式设置语言是所有web页面的最佳实践。了解文本语言将有助于自动翻译工具、屏幕阅读器和其他辅助软件。

lang="en"属性使用ISO语言标记告诉浏览器文本是英文的。在这种情况下,浏览器将选择其默认的英语连字符字典,通常会用美国英语的连字符。虽然美国英语和其他国家在拼写和发音(因此连字符)上有很大差异,但在葡萄牙语等语言上的差异可能更大。解决方案是在语言中添加一个“区域”,以便浏览器知道哪个是最合适的连字符字典。例如,要指定巴西葡萄牙语或英式英语:

<html lang="pt-BR">
<html lang="en-GB">

接在在CSS中添加hyphens属性来打开自动连字符:

hyphens: auto;

到目前为止,Safari和IE/Edge浏览器中还需要添加相应的前缀:

-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;

当然,如果你使用Autoprefixer插件的话,你不需要太担心前缀的问题。

设置连字符不仅仅是打开连字符。CSS文本模块(CSS Text Module Level 4)引入了和布局软件的一些特性。这些特性提供了不同的方法来定义文本中出现了多少连字符。

限制连字符前后的单词长度和字符数

如果你用连字符连接短单词,会让阅读更难。同样,你也不希望在连字符之前的行上留下太少的字符,或者在连字符之后被推到下一行。从经验上来看,只允许至少有6字母长的单词用连字符来连接,在单词断开之前至少留下3个字符,并在下行至少保留2个字符

在CSS中,可以使用hyphenate-limit-chars属性设置这些限制。该属性具有三个用空格符隔开的值:

  • 第一个值是连字符的最小字符限制
  • 第二个值是断字前最小字符数
  • 第三个值是断字后最小字符数

比如:

hyphenate-limit-chars: 6 3 2;

效果如下:

如果hyphenate-limit-chars设置了默认值auto,也就是说三个值都是相同(都是 auto)。这意味着浏览器会根据当前的语言和布局方式选择最佳的设置。CSS文本模块建议浏览器采用的是5 2 2作为断字连接的规则(我认为这会导致太多的连字符),但是浏览器可以根据自己的需要随意更改。

到目前为止,只有IE和Edge浏览器支持这个属性,但Safari确支持的是文本模块早期草案中的一些规则。这意味着,如果你让效果在众多浏览器中得到较一致的效果,就需要像下面这样使用:

/* 文本模块中老语法 */
-webkit-hyphenate-limit-before: 3;
-webkit-hyphenate-limit-after: 2;

/* 当前的建议  */
-moz-hyphenate-limit-chars: 6 3 2; /* 还未得到支持 */
-webkit-hyphenate-limit-chars: 6 3 2; /* 还未得到支持 */
-ms-hyphenate-limit-chars: 6 3 2;
hyphenate-limit-chars: 6 3 2;

限制连续连字符行数

出于美学上的考虑,可以限制连续边字符的行数。默认情况之下,CSS并不限制连续连字符的数量,但我们可以使用hyphenate-limit-lines属性来指定。

-ms-hyphenate-limit-lines: 2;
-webkit-hyphenate-limit-lines: 2;
hyphenate-limit-lines: 2;

如果你不想要限制的时候,可以使用 no-limit值来删除限制。

避免在段落的最后一行使用连字符

在排版本的时候,如果你不想在段落的最后一行出现连字符。那么可以在CSS中使用hyphenate-limit-last属性来进行设置:

hyphenate-limit-last: always;

通过设置边字符区域来减少连字符

默认情况下,浏览器可以使用hyphenate-limit-charshyphenate-limit-lines属性来设置连字符规则和连字符行数的设置。这两个属性可以很好的控制连字符,但是同时也有可有会面临出现多个连字符,从美心上来说,是有点不太友好。

考虑一个左对齐的段落,右边缘就有可能出现参差不齐。我们可以使用hyphenate-limit-charshyphenate-limit-lines两个属性来改变这一现象,但这样一来会造成另一现象,同一个段落有可能会出现多个连字符。不过,值得庆幸的是,我们可以hyphenate-limit-zone属性来改变这一现象。该属性可以用来指定行最后一个单词和文本框边框之间允许的最大空间。

hyphenate-limit-zone: 8%

有了这些基础性的了解,我们在排版的时候,就可以将他们放在一起:

p {
    hyphens: auto;
    hyphenate-limit-chars: 6 3 3;
    hyphenate-limit-lines: 2;   
    hyphenate-limit-last: always;
    hyphenate-limit-zone: 8%;
}

这样一来,你的排版效果会更美一些。

特别声明,上面的内容来自于 @clagnut的《All you need to know about hyphenation in CSS》一文。事实上排版一直都是Web相关知识中较为难攻克的部分。如果你感兴趣的话,可以购买@clagnut的书《Web Typography》。

Sass颜色函数和CSS自定义属性的结合

前几天看阅读了@echo的《聊一聊前端换肤》一文,非常受益。在Web中对页面或组件等换肤的情景非常常见。而这些都和颜色相关打交道。时至今日,在CSS的color-mod()函数可以很好的修改颜色,但不幸的是,支持的浏览器非常的少见。但在CSS处理器中,很多同学会借助处理器的一些特性来做颜色相关的处理,比如Sass的颜色函数,他们就可以帮助我们做一些事情。

不过,随着CSS自定义属性出来之后,有不少文章在介绍使用CSS自定义属性来实现换肤的效果:

但我不想在这里聊怎么换肤,上面的文章足够你了解这方面相关的知识。我想和大家聊另一个问题。那就是 @Claudia Romano的《How to combine SASS color functions and CSS Variables》一文中提到知识点。

Sass颜色函数和CSS自定义属性结合将会产生什么?

简单地说,通过Sass的@mixin来实现类似Sass颜色函数和CSS的color-mod()的功能,比如alpha(),可以像下面这样来写:

@mixin alpha($property, $color-variable, $opacity) {
    $color-variable-h: var(#{$color-variable+'-h'});
    $color-variable-s: var(#{$color-variable+'-s'});
    $color-variable-l: var(#{$color-variable+'-l'});
    #{$property}: hsla($color-variable-h, $color-variable-s, $color-variable-l, $opacity);
}

在:root中设置三个自定义属性:

:root {
    --color-primary: hsl(220, 90%, 56%);
    --color-primary-h: 220;
    --color-primary-s: 90%;
    --color-primary-l: 56%;
}

.component {
    @include alpha(background-color, --color-primary, 0.2);
}

除了@mixin之外,还可以使用Sass的function来实现类似的功能:

@function alpha($color, $opacity){
    $color: str-replace($color, 'var(');
    $color: str-replace($color, ')');
    $color-h: var(#{$color+'-h'});
    $color-s: var(#{$color+'-s'});
    $color-l: var(#{$color+'-l'});
    @return hsla($color-h, $color-s, $color-l, $opacity);
}

@function str-replace($string, $search, $replace: '') {
    $index: str-index($string, $search);
    @if $index {
        @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
    }
    @return $string;
}

这样一来,使用的时候会更友好:

.component {
    background-color: alpha(var(--color-primary), 0.2);
}

使用类似的方法还可以创建其他的一些颜色函数功能,比如lightness()darken()saturation()之类以及color-mod()中的功能。感兴趣的同学可以自己撸一下。

原生的延迟加载lazy-loading

IntersectionObserver特性使延迟加载比以前更容易、更有效,但要真正做到这一点,还是有一些限制条件的,比如删除src。和新的loading属性相比还是有一定的差距:

loading属性允许浏览器延迟加载屏幕外的imgiframe。该属性有三个值:

  • lazy:延迟加载
  • eager:不适合延迟载加。负载
  • auto:浏览器将决定是否延迟加载

使用的时候可以直接在imgiframe标签上显式设置loading属性值,比如:

<!-- Lazy-load an offscreen image when the user scrolls near it -->
<img src="unicorn.jpg" loading="lazy" alt=".."/>

<!-- Load an image right away instead of lazy-loading -->
<img src="unicorn.jpg" loading="eager" alt=".."/>

<!-- Browser decides whether or not to lazy-load the image -->
<img src="unicorn.jpg" loading="auto" alt=".."/>

<!-- Lazy-load images in <picture>. <img> is the one driving image 
loading so <picture> and srcset fall off of that -->
<picture>
<source media="(min-width: 40em)" srcset="big.jpg 1x, big-hd.jpg 2x">
<source srcset="small.jpg 1x, small-hd.jpg 2x">
<img src="fallback.jpg" loading="lazy">
</picture>

<!-- Lazy-load an image that has srcset specified -->
<img src="small.jpg"
    srcset="large.jpg 1024w, medium.jpg 640w, small.jpg 320w"
    sizes="(min-width: 36em) 33.3vw, 100vw"
    alt="A rad wolf" loading="lazy">

<!-- Lazy-load an offscreen iframe when the user scrolls near it -->
<iframe src="video-player.html" loading="lazy"></iframe>

有关于这方面更详细的介绍,可以阅读@Addy Osmani的博文《Native image lazy-loading for the web!》。

不规则阴影的处理方案

在Web的实际开发中,有的时候需要给不规则的形状添加阴影效果,比如下图这样的:

给元素盒子添加阴影,大家首先能想到的是box-shadow属性:

虽然在某些场景之下,使用box-shadow配合其他的CSS属性,比如positionz-indexclip能达到预期的效果。但在某些场景下使用box-shadow实现阴影效果,难度较大,效果也较差,比如下面这样的场景:

或者下图这样的不规则图形:

不过,在CSS的世界中,除了box-shadow之外还有另一个属性也可以实现阴影效果,这个属性是filter:drop-shadow()

虽然box-shadowfilter: drop-shadow()都能给元素添加盒子阴影,但两者还是有明显的差异性的,如下图所示:

有关于box-shadowfilter:drop-shadow()两者差异性的相关介绍,可以阅读@ChokCoco的《你所不知道的 CSS 阴影技巧与细节》一文。

如果你阅读完了上面的文章,我想针对不规则的图形(即clip-path绘制出来的图形)添加阴影的方案就有答案了。

使用filter: drop-shadow()clip-path可以完美的给不规则图形添加阴影效果

比如:

.tag-wrap {
    filter: drop-shadow(-1px 6px 3px rgba(50, 50, 0, 0.5));
}
.tag {
    clip-path: polygon(30px 0%, 100% 0%, 100% 100%, 30px 100%, 0 50%);
}

得到的效果如下:

扩展阅读

CSS中对齐的那些事儿

@Rachel Andrew在她的新教程《How To Align Things In CSS》中介绍了CSS中有关于对齐的一些事情,这是一篇有关于介绍对齐方式最全面的一篇文章,这也是一篇非常有意思的文章。文章最后总结了一些使用规则:

  • 如果你需要对文本或内联元素设置对齐方式,则可以使用text-alignvertical-alignline-height(水平对齐设置使用text-align,垂直对齐设置使用vertical-align
  • 如果你想在一个容器中设置一个或多个元素的水平垂直居中,则可以将容器设置为flex,然后设置align-items: centerjustify-content: center
  • 在网格布局中,以align-开头的属性是按块方向工作;以justify-开头的则是按内联方向工作
  • 在Flexbox布局中,以align-开头的属性是在侧轴方向工作,以justify-开头的则是按主轴方向工作
  • justify-contentalign-content属性可以分配容器额外的空间。如果在Flexbox或Grid容器中没有额外的空间,它们则什么都不做
  • 如果你想在Flexbox中使用justify-self,那么设置marginauto可能会达到你想要的效果(因为在Flexbox中justify-self在Flex项目中是用不上的,但可以借助margin设置auto来达到一定的效果)

正如上面所述,CSS中有关于对齐的方式就这些,但随着CSS的逻辑属性CSS的书写模式的出现,不管是text-alignvertical-align还是CSS Box Alignment中提供的一些属性,都会有相应的差异性变化。

除此之外,在CSS中还有一个text-align-last属性,可以用来控制一个块的最后一行或<br />标签断行的最后一行的对齐方式。有关于这方面的详细介绍可以点击这里阅读

扩展阅读

小结

又是一篇迟来的文章。在这篇文章中主要围绕着 断行排版本连字符Sass颜色函数和CSS自定义属性的结合原生延迟加载不规则图形阴影CSS中对齐的那些事儿五个方面展开。最后希望这几个点对大家日常的开发有所帮助。如果你在这方面有更深的理解或者相关优秀的教程,欢迎在下面的评论中与我们一起分享。Air Jordan 30.5 Shoes