前端开发者学堂 - fedev.cn

Web技巧(09)

发布于 大漠

这一期中我们主要来聊聊全屏的事情。对于全屏的布局,大家可能首先想到的是100%(或100vw)来实现,但如果你要在一个限宽的容器中实现一个全屏效果呢?比如说,一个Banner区全屏显示。类似这样的效果在PC端是非常常见的一个效果。可能会有很多同学会说,这样的效果有什么好聊的,不是非常简单的Layout吗?其实还是有点事情可聊的。如果你感兴趣,不仿继续往下阅读。

全屏宽度的事情

在Web布局中,特别是在PC端中,常常可以看到这样的设计风格:内容居中,然后Banner区全屏。这也就是标题所说的效果,限宽的容器中实现全屏效果。那么问题来了,在实际中如何实现在限宽的容器中实现全屏效果。比如下面的设计风格:

看到上图的效果,我们可能首先会想到从HTML结构上来做相应的处理:

<div class="banner">
    <div class="container">
    </div>
</div>

对应的CSS样式:

.banner .container {
    width: 100%
}

如果对于多个区域全屏和多个区域限宽居中呢?如果还是从结构上做处理的话,可能会:

<header>
    <div class="wrapper">
    </div>
</header>

<div class="full-width">
    <div class="wrapper">
    </div>
</div>

CSS并不会太复杂:

.full-width {
    width: 100%;
}
.wrap {
    width: 80%;
    max-width: 24em;
    margin: 0 auto;
}

这其实很简单。如果我们换过一个环境或提高限制条件呢?假设你是在为一个CMS系统做开发(你并没有自主修改HTML的权限)。即你的结构有能都是这样的一个模式:

<div class="container">
    <header></header>
    <div clas="banner"></div>
    <main></main>
    <footer></footer>
</div>

.container中设置一个限制宽度,比如:

.container {
    width: 80%;
    max-width: 80vw;
    margin: 0 auto;
}

基于这样的一个Layout结构,如果header.bannerfooter区域需要全屏显示。在不修改HTML结构的情况之下,如何实现需要的效果。

负margin和正padding相互抵销

大家是否还记得等高布局,在等高布局的实现方案中就有一个负margin和正padding相互抵销的方案。那么如果仅实现一个全屏的背景颜色也可以使用该方案:

header {
    margin: 0 -9999rem;
    padding: 1rem 9999rem;
}

负责margin和正border相互抵销

和前面的一个方案类似,只不过把正padding换成了border

.banner {
    border-left: 600rem solid maroon;
    border-right: 600rem solid maroon;
    margin: 0 -600rem;
}

vw和calc()相结合

使用vwcalc()两者的结合可以让事情变得更为简单,比如:

.full-width { 
    width: 100vw; 
    position: relative; 
    left: 50%; 
    right: 50%; 
    margin-left: -50vw; 
    margin-right: -50vw; 
}

在CSS中,我们可以借助transform中的translate()来替代leftright,上面的示例代码可以变成:

.full-width { 
    width: 100vw; 
    transform: translateX(calc(( 960px - 100vw ) / 2));  // 假设限宽的容器宽度为960px
}

上面的代码咱们继续优化一下:960px相当于100%,这样一来960px / 2也就相当于50%;对应的100vw / 2就变成了50vw。这样上面的代码就变成了:

.full-width {
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
}

如果你使用Sass这样的CSS处理器,你还可以将其封装成一个@mixin

@mixin full-width($support-type: margin,$min-width:null){ 
    @if $support-type == 'margin' { 
        margin-left: calc(-50vw + 50%); 
        margin-right: calc(-50vw + 50%); 
        // margin-left: calc(-100vw / 2 + #{$min-width} / 2); 
        // margin-right: calc(-100vw / 2 + #{$min-width} / 2); 
    } 
    @if $support-type == 'position' { 
        width: 100vw; 
        position: relative; 
        left: 50%; 
        right: 50%; 
        margin-left: -50vw; 
        margin-right: -50vw; 
    } 
    @if $support-type == 'translate' { 
        width: 100vw; 
        transform: translateX(calc((#{$min-width} - 100vw)/2)); 
    } 
}

有了上述定义的混合宏,在实际使用的时候,只需要向下面这样调用:

.full-width {
    @include full-width(margin,960px);
}

使用vwcalc()函数来实现限宽容器中任何一个单一元素实现全屏布局。另外,vw还可以配合伪元素、padding或者说百分比和padding也可以实现一些类似的布局效果:

有关于这方面更详细的介绍可以阅读:

关于display属性的一二

Web技巧第四期中末尾向大家介绍了CSS中重要的属性之一display,在未来的display中可以使用两个值。而@Rachel Andrew花了三篇文章的篇幅来介绍CSS的display属性:

如果想对display有一个深入的了解,那么这几篇文章对你是有较大的参考价值或者文章中相关的内容是非常值得我们去深挖。当然,想更深入的把display聊的清楚一些,那么我们很有必要花更多的时间来梳理。如果你感兴趣的话,欢迎关注后续相关的更新,我将会花一到两篇的篇幅和大家重新来聊display。如果你不想等的太久,除了上面的文章之外,下面这几篇文章也是有助于你更好的理解display

字体图标使用的兼容性

在《Web中的图标》一文中主要和大家一起聊了聊Web中的图标(Icon图标)如何应该,应该怎么去选择。虽然SVG的Icon在实际使用中已经非常的成熟了:

但还是有很多同学在使用字体图标,而且有关于字体图标相关的介绍也非常的多:

但字体图标的使用过程中会存在很多的问题。@zachleat在《The Scoville Scale of Web Font Loading Opinions》为Web字体加载做了一个主题的介绍,而且有关于这方面的优秀教程,在互联网上大把:

而字体图标和字体加载存在一定的兼容性问题。简单地说,字体图标似乎存在Web标准之外。换句话说就是font-display没有与图标字体兼容的有效值。

加载字体图标时,通常不希望有一个降级文本(回退文本)渲染。它不是典型的无样式文本(FOUT)场景。如果字体图标没有回退文本渲染,谁都不知道字体加载未成功的时候会看到什么。

你可有在访问有字体图标的Web页面时,字体未加载或加载失败时看不到图标,而是一个带颜色的方框

使用字体图标都会借助CSS的@font-face属性,在@font-face指令中使用font-display来加载自定义字体。这个属性可以添加以下的值:

  • auto:默认值。典型的浏览器字体加载的行为会发生,也就是使用自定义字体的文本会先被隐藏,直到字体加载结束才会显示
  • swap:后备文本立即显示直到自定义字体加载完成后再使用自定义字体渲染文本。在大多数情况下,这就是我们所追求的效果
  • fallback:这个可以说是autoswap的一种折中方式。需要使用自定义字体渲染的文本会在较短的时间不可见,如果自定义字体还没有加载结束,那么就先加载无样式的文本。一旦自定义字体加载结束,那么文本就会被正确赋予样式
  • optional:效果和fallback几乎一样,都是先在极短的时间内文本不可见,然后再加载无样式的文本。不过optional选项可以让浏览器自由决定是否使用自定义字体,而这个决定很大程度上取决于浏览器的连接速度。如果速度很慢,那你的自定义字体可能就不会被使用
  • block:为字体提供一个短暂的阻塞周期和无限的交换周期,它将使用不可见的文本长达3s,并显示回退文本,直到Web字体加载完成。这是最佳选项,但仍然不是很好

有关于font-display更详细的介绍可以阅读《font-display的用法》一文。

要解决这些问题,可以使用CSS字体加载API强制不可见的文本,直到图标字体成功加载。或者使用使用SVG图标。

七个有用的JavaScript小技巧

@David Walsh整理了使用JavaScript的几个小技巧

获取数组的唯一值

通过...new Set()得到一个唯一值的数组:

var j = [...new Set([1, 2, 3, 3])]
>> [1, 2, 3]

数组和布尔值

通过mapfilter来过滤掉数组中的布尔值(比如0undefinednullfalse等):

myArray.map(item => {
    //... 
}).filter(Boolean)

比如:

[0, undefined, false, 1, 23].map(item=>{ return item }).filter(Boolean)
>> [1, 23]

创建空对象

可以使用{}来创建一个看起来像空的对象,但该对象仍然有一个__proto__hasOwnProperty和其他对象方法。然而,有一种方法可以创建一个纯"dictionary"对象:

let dict = Object.create(null)
dict.__proto__ === "undefined"
>> false

合并对象

在JavaScript中合并多个对象的需求一直存在,特别是当我们开始创建类和带有选项的组件时:

const person = {
    name: 'David Walsh',
    gender: 'Male'
}
const tools = {
    computer: 'Mac',
    editor: 'Atom'
}
const attributes = {
    handsomeness: 'Extreme',
    hair: 'Brown',
    eye: 'Blue'
}

const summary = {...person, ...tools, ...attributes}

需要函数参数

能够为函数参数设置默认值是JavaScript的一个很棒的功能,但看看这个技巧,它要求为给定的参数传递值:

const isRequired = () => {
    throw new Error('param is required')
}

const hello = (name = isRequired()) => {
    console.log(`hello ${name}`)
}

解构的别名

解构是一个非常受欢迎的JavaScript,但有时我们更喜欢用其他的名称引用这些属性,所以我们可以利用别名:

const obj = { x: 1}
const { x } = obj
const {x: otherName} = obj

获取查询字符串参数

多年来,我们编写粗糙的正则表达式来获取查询字符串值,但那些日子已经一去不复返了,输入URLSearchParams API即可:

// Assuming "?post=1234&action=edit"

var urlParams = new URLSearchParams(window.location.search);

console.log(urlParams.has('post')); // true
console.log(urlParams.get('action')); // "edit"
console.log(urlParams.getAll('action')); // ["edit"]
console.log(urlParams.toString()); // "?post=1234&action=edit"
console.log(urlParams.append('active', '1')); // "?post=1234&action=edit&active=1"

有关于数组和对象更多的介绍可以点击:

总结

这一期中我们主要一起聊了聊如何在限宽的容器中让某部分实现全屏显示,除了在结构上实现所需的效果之外,还可以在单个元素上借助一些CSS的特性来完成,比如负margin和正padding、或者负marginborder这样的互负抵销的方式;也可以使用vwcalc()让事情变得还更简单。

display是CSS的重要内容之一,@Rachel Andrew的三篇博文,让我们对CSS的display有了一个更深层次的理解,在今年的布局或者在使用display会变得更明了。另外图标是Web中常用的一部分,这里罗列了字体图标使用的一些教程以及如何借助font-display来让字体加载让用户有一个更好的体验。虽然font-display可以对字体加载做一些优化,但使用字体图标依旧是有一些缺陷的,建议大家还是考虑使用SVG图标。

最后,把@David Walsh整理的几个JavaScript小技巧列入到这一期,希望这些小技巧能在实际开发中给大家带来一些帮助。