SilenceHVK / blog

:books: :octocat: Github static blog post, experience the fun of using Issues.Welcome star( 静态博客文章,体验一下使用 Issues 的乐趣,欢迎 star )个人博客地址:blog.hvkcoder.me/love
https://github.com/SilenceHVK/Articles/issues
MIT License
231 stars 9 forks source link

【HTML + CSS】CSS 响应式布局 #65

Open SilenceHVK opened 5 years ago

SilenceHVK commented 5 years ago

  响应式开发的本质是针对多种屏幕做适配,首先需要掌握几个基本概念:

使用 rem 实现响应式布局

  rem(font size of the root element)是 CSS 的计量单位,表示相对于根(即 html)元素的字体大小。其主要用于移动 Web 开发,以适配不同尺寸的屏幕。

  rem 的兼容可以通过 caniuse 查询

rem 兼容

  由于 rem 单位是相对于网页根元素的字号大小而定,所以实现 rem 布局开发时,首先要做的就是对根元素的字号赋值。

    html{ font-size:12px; }

我们将网页根元素的字号设置为 12px,此时 rem 相对于网页根元素字号为 1rem = 12px。故此转换 rem 的公式则为

    rem值 = 元素实际 px 值 / 网页根元素的字号

下面通过 rem 实现一个简单的布局 【预览

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <meta http-equiv="X-UA-Compatible" content="ie=edge">
            <title>Rem Case</title>
            <style>
                body {
                    font-size: 12px;
                    margin: auto;
                }

                .btns {
                    width: 10rem;
                    margin: 0 auto;
                }

                .btns > a {
                    float: left;
                    width: 2.5rem;
                    text-align: center;
                    padding-top: 0.2rem;
                }

                .btns > a > i {
                    display: inline-block;
                    width: 1.2rem;
                    height: 1.2rem;
                    background: gray;
                    border-radius: 50%;
                }

                .btns>a>span {
                    display: block;
                    line-height: 0.8rem;
                    font-size: 14px;
                }
            </style>
        </head>
        <body>
            <div class="btns">
                <a>
                    <i></i>
                    <span>英语</span>
                </a>
                <a>
                    <i></i>
                    <span>日语</span>
                </a>
                <a>
                    <i></i>
                    <span>德语</span>
                </a>
                <a>
                    <i></i>
                    <span>法语</span>
                </a>
                <a>
                    <i></i>
                    <span>韩语</span>
                </a>
                <a>
                    <i></i>
                    <span>小语种</span>
                </a>
                <a>
                    <i></i>
                    <span>教学</span>
                </a>
                <a>
                    <i></i>
                    <span>职场</span>
                </a>
            </div>
        </body>
    </html>

最后加上最关键的重置元素字号脚本

    (function (window, document) {
        'use strict';
        // 获取网页根元素
        var html = document.documentElement || document.querySelector('html');
        // 重置根元素字号
        function resetFontSize() {
            // 获取根元素的宽度
            var width = html.getBoundingClientRect().width;
            // 设置一个最大宽度值
            if (width > 640) width = 640;
            html.style.fontSize = (width / 10) + 'px';
        }

        resetFontSize();
        window.addEventListener('resize', resetFontSize, false);
    })(window, document);

  rem 确实有效的解决了响应式布局,但却并非完美:

使用 vw、vh、vmin、vmax 实现响应式布局

  vwvhvminvmaxrem 相同都是 CSS3 中新引入的一种计量单位。不同于 rem 它们所表达的含义如下:

单位 含义
vw 等于视口宽度的 1%
vh 等于视口高度的 1%
vmin 相视的宽度或高度,取决于哪个更小
vmax 相对于视的宽度或高度,取决于哪个更大

  vwvhvminvmax 的兼容可以通过 caniuse 查询

vm 兼容

  在使用 vwvhvminvmax 之前我们需要认识一下视口。

  以 PPK大神 在其文章 A tale of two viewports (一)A tale of two viewports (二) 以及 Meta viewport 三篇文章 中提出关于视口的解释:

The function of the viewport is to constrain the element,which is the uppermost containing block of your site.

译:视口的功能是约束 html 元素,它是网站上的包含区块。

The viewport, in turn, is exactly equal to the browser window: it’s been defined as such. The viewport is not an HTML construct, so you cannot influence it by CSS. It just has the width and height of the browser window — on desktop.

译:视口与浏览器窗口完全相同,但它并不是 HTML 结构,因此你不能通过 CSS 来影响它。在桌面端,视口只是具有浏览器窗口的高度与宽度。

  以上是我在原文中截取的两段关于桌面端的视口概念,从中总结得知:在桌面端,视口就是浏览器的可视化区域,其只是具有浏览器窗口的高度和宽度,使用 document.documentElement.clientWidth/Height 获取视口宽高

Imagine the layout viewport as being a large image which does not change size or shape. Now image you have a smaller frame through which you look at the large image. The small frame is surrounded by opaque material which obscures your view of all but a portion of the large image. The portion of the large image that you can see through the frame is the visual viewport. You can back away from the large image while holding your frame (zoom out) to see the entire image at once, or you can move closer (zoom in) to see only a portion. You can also change the orientation of the frame, but the size and shape of the large image (layout viewport) never changes.

译:设想布局视口是一个不改变形状和大小的大图像,现在你有一个更小的框架通过它你可以看到大的图像。这个框架被不透明的材料包围,遮挡了除大图像的一部分之外的其他部分。你可以通过框架看到的大图像的部分就是视觉视口( visual viewport)。你可以缩小大图像直至看到整个大图像,或者你可以放大到只看其一部分。你可以去改变框架的方向,但是这个大图像(布局视口)的大小和形状永远不会改变.

The visual viewport is the part of the page that’s currently shown on-screen.The user may scroll to change the part of the page he sees, or zoom to change the size of the visual viewport.

译:视觉视口就是当前显示在屏幕上页面的一部分。用户可以通过滚动改变看到的页面的一部分,或者缩放以更改视觉视口的大小。

However, the CSS layout, especially percentual widths, are calculated relative to the layout viewport, which is considerably wider than the visual viewport.

译:然而,CSS 布局,特别是百分比的宽度,是相对于布局视口计算的,它要比视觉视口宽的多。

How wide is the layout viewport? That differs per browser. Safari iPhone uses 980px, Opera 850px, Android WebKit 800px, and IE 974px.

译:布局视口有多宽呢?每个浏览器是不同的,Safari 使用 980px,Opera 850px, Android WebKit 800px, IE 974px。

The ; originally an Apple extension but meanwhile copied by many more browsers. It is meant to resize the layout viewport.

译:,最初是苹果的扩展,但同时被多个浏览器采纳,它是用于调整布局视口端口的大小。

  以上是我在原文中对移动端视口概念的截取,从中总结可得知:

移动端的视口分为三部分:

  1. 视觉视口(visual viewport):就是设备的屏幕区域,但是它所对应的并不是指屏幕区域里的物理像素,而是 CSS 像素。当用户缩小或放大时,测量会发生变化,因为更多或更少的 CSS 像素会融入屏幕。使用 window.innerWidth/Height 获取视觉视口的宽高。
  2. 布局视口(layout viewport):与视觉视口不一样,它是为了解决PC 端网站在移动端显示不佳的一个解决方案,它宽高不会改变,使用 document.documentElement.clientWidth/Height 来获取布局视口的宽高。
  3. 理想视口(ideal viewport):它是基于布局视口的,用于调整布局视口端口的大小。

  既然提到了 理想视口(ideal viewport),那么就不得不普及一下 <meta name="viewport">

viewport 属性

  viewport 是指屏幕上能用来显示网页的区域,默认情况下大多数设备的 viewport 的宽度都是 980 像素,可以通过在 heade 元素中增加 meta 标签来设置 viewport 属性:

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
        </head>
        <body></body>
    </html>

viewport 下包含以下属性:

通过设置 viewport 属性,可以调整用户界面的逻辑大小,页面 CSS 中的大小均以 viewport 为基准。

vw、vh、vmin、vmax 的使用

  基础的东西说完了,接着回到 vwvhvminvmax 的使用,它们相对于 PC 端浏览器的视口就是浏览器的可视化区域 ,而在移动端则为布局视口,还是以第一个案例为例,使用 vw 实现布局【预览】:。

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>VW Case</title>
    <link rel="shortcut icon" href="../../assets/images/icon/favicon.ico" type="image/x-icon">
    <style>
        body {
            font-size: 12px;
            margin: auto;
        }

        .btns {
            width: 80vw;
            margin: 0 auto;
        }

        .btns>a {
            float: left;
            width: 20vw;
            text-align: center;
            padding-top: 10px;
        }

        .btns>a>i {
            display: inline-block;
            width: 10vw;
            height: 10vw;
            background: gray;
            border-radius: 50%;
        }

        .btns>a>span {
            display: block;
            line-height: 3vw;
            font-size: 14px;
        }
    </style>
</head>

<body>
    <div class="btns">
        <a>
            <i></i>
            <span>英语</span>
        </a>
        <a>
            <i></i>
            <span>日语</span>
        </a>
        <a>
            <i></i>
            <span>德语</span>
        </a>
        <a>
            <i></i>
            <span>法语</span>
        </a>
        <a>
            <i></i>
            <span>韩语</span>
        </a>
        <a>
            <i></i>
            <span>小语种</span>
        </a>
        <a>
            <i></i>
            <span>教学</span>
        </a>
        <a>
            <i></i>
            <span>职场</span>
        </a>
    </div>
</body>

</html>

  vwvhvminvmax 的出现给我的感觉显得有些鸡肋,有点像 %,但与百分比最大的不同则是 %是相对于父元素的大小设定的比率,vwvh 是视口大小决定的。在使用它的过程中,个人认为它并不适合去做布局,而是去做一些元素大小的限制。当然,也是因为个人能力有限,并没有悟透,希望能够得到大神的指点。

Flex 弹性盒布局

  在 Felx 出现之前,布局基于盒模型,依赖 displaypositionfloat 样式属性。但是使用时需要清除浮动,并且对于一些特定布局的实现非常不方便,下面就让我们来看一下,Felx 布局的基本概念,如图所示:

flex 容器

  采用 Flex 布局的容器称为 Flex 容器flex container),所有子元素自动成为容器成员,称为 Flex 项目(flex item)。容器默认存在两根轴:

项目默认沿主轴排列,单个项目占据主轴的空间叫做 项目主轴大小(main size),占据交叉轴空间叫做 项目交叉轴大小(cross size)

Flex 容器属性

1. display

说明:通过设置 display 属性的值为 flex 或 inline-flex 将其定义为弹性容器。

语法:display: flex | inline-flex

display:flex

display:inline-flex

2. flex-direction

说明:决定主轴的方向(项目的排列方向)。该属性的反转值不会改变元素的绘制,只改变流动方向。

语法:flex-direction: row | row-reverse | column | column-reverse

flex-direction-row

flex-direction-row-reverse

flex-direction-column

flex-direction-column-reverse

3. flex-wrap

说明:控制 flex 容器是单行或多行。

语法:flex-wrap: nowrap | wrap | wrap-reverse

flex-wrap-nowrap

flex-wrap-wrap

flex-wrap-wrap-reverse

4. flex-flow

说明:复合属性,设置 flex 项目排列方式。

语法:flex-flow: <flex-direction> || <flex-wrap>

5. justify-content

说明:设置 flex 项目主轴上的对齐方式。

语法:justify-content: flex-start | flex-end | center | space-between | space-around

justify-content-flex-start

justify-content-flex-end

justify-content-center

justify-content-space-between

justify-content-space-evenly

justify-content-space-around

6. align-items

说明:设置 flex 项目交叉轴上的对齐方式。

语法:align-items: stretch | flex-start | flex-end | center | baseline

align-items-stretch

align-items-flex-start

align-items-flex-end

align-items-center

align-items-baseline

7. algin-content

说明:用于修改 flex-wrap 属性的行为。类似与 justify-content,但它不是设置弹性子元素的对齐,而是设置各个行的对齐。

语法:align-content: stretch | flex-start | flex-end | center | space-between | space-around

align-content-stretch

align-content-flex-start

align-content-flex-end

align-content-center

align-content-space-between

align-content-space-around

Flex 项目属性

1. flex-grow

说明:定义项目的扩展比例,根据 Flex 容器的子元素所设置扩展因子作为比率来分配剩余空间。对于 flex 项目宽度未超出 flex 容器宽度时,生效。

语法:flex-grow: <number> (default 0)

用数值来定义扩展比率。不允许是负值。

flex-grow

flex 项目扩展宽度 = (flex 容器 - flex项目宽度) / (flex-grow 比率)

div1 实际宽度 = 180px + ( 500px - (180px + 280px)) / ( 1 + 1 )

div2 实际宽度 = 280px + ( 500px - (180px + 280px)) / ( 1 + 1 )

2. flex-shrink

说明:定义项目的缩小比例,根据 Flex 容器的子元素所设置收缩因子作为比率来分配收缩空间。****

语法:flex-shrink: <number> (default 1)

用数值来定义缩小比率。不允许是负值。

flex-shrink

flex 项目缩小宽度 = (flex 项目宽度 flex-shrink 比率) / ( 所有flex项目的乘积和 ) 超出flex容器宽度

div1 实际宽度 = 300px - (300px * 1) / (300px * 1 + 280px * 1) * (300px + 280px - 500px)

div2 实际宽度 = 280px - (280px * 1) / (300px * 1 + 280px * 1) * (300px + 280px - 500px)

3. flex-basis

说明:定义在分配剩余空间之前,项目占据的主轴空间。可以理解为与 width 一样。

语法:flex-basis: <length> | auto (default)

flex-basis 应用准则:

content -> width -> file-basis (limited by max|min-width)

4. flex

说明:flex 是 flex-growflex-shrinkflex-basis 的复合属性。

语法:flex: <flex-grow> || <flex-shrink> || <flex-basis>

5. order

说明:定义 flex 项目 的排列顺序,值越小,排列越靠前。

语法:order: <number> (default 0)

6. align-self

说明:设置单个项目的对齐方式,可覆盖 flex 容器 设置的 align-items 属性。

语法:align-self: auto | flex-start | flex-end | center | baseline | stretch