zoukankan      html  css  js  c++  java
  • 《深入解析css》—精通布局

    前言:所有内容与示例源码源于基思·J·格兰特的《深入解析css》,文章用于笔记整理。源码仓库

    一、浮动布局

    引入

    浮动元素会被移出正常文档流,文档流会重新排列并包围浮动元素。这种布局在报纸和杂志中很常见。

    image.png

    容器折叠

    浮动元素的高度不会加到父元素上。所以当子元素的高度比父元素大时,父元素不会撑开。解决办法:使用clear属性。将一个元素放在主容器的末尾,并对它使用clear,这会让容器扩展到浮动元素下面

    <style>
        .container{
            max-1080px;
            margin:0 auto
        }
        .children{
            float:left;
        }
    </style>
    
    <div class=container>
        <h1>标题</h1>
        <div class=children></div>
        <div class=children></div>
        ...
        <div style="clear:both"></div>
    </div>
    

    双容器模式居中法

    image.png

    清除浮动

    • 在父元素里的末尾加上一个空标签(如上)

    • 用伪元素清除浮动

      .clearfix::after{
          display:block;
          content:" ";
          clear:both
      }
      

      上方的写法不能解决外边距折叠问题,下面是修改后的方案:

    • 伪元素清除浮动修改版

      .clearfix:before,.clearfix:after{
          content:'';
          display:table;
      }
      .clearfix:after{
          clear:both;
      }
      
    • 给父级容器标签加上overflow属性(非visible)

      .container{
        overflow:hidden|auto|scroll
      }
      

    浮动陷阱

    浏览器会将浮动元素尽可能地放在靠上的地方,所以有时候会发生这种情况:

    image.png

    解决办法:清除每行的第一个元素上面的浮动。假设你一行需要放两个浮动元素,那么你可以这样写:

    .box:nth-child(odd){
        clear:left
    }
    

    如果每行需要三个元素:

    .box:nth-child(3n+1){
        clear:left
    }
    

    上面这种清除每行浮动的技术要求知道每行有几个元素。如果宽度不是通过百分比来定义的,最好使用别的布局方案,比如Flexbox或者inline-block元素。

    媒体对象和BFC

    图片在一侧,文字在图片旁边。Web开发人员Nicole Sullivan把这种布局称作“媒体对象”。这种布局模式有好几种实现方案,包括Flexbox和表格布局,但这里我们用浮动。

    <div class="media">
    	<img class="media-image"src="shoes. png">
    	<div class="media-body">
    		<h4>Change it up</h4>
    		<p>
                Don't run the same every time you hit the road. 
                Vary your pace, and vary the distance of your 
                runs.
    		</p>
    	</div>
    </div>
    
    .media-image{
        float:left
    }
    .media-body h4{
        margin-top:0
    }
    

    image.png

    上面的方式就是给正文建立一个块级格式化上下文(block formatting context, BFC)。BFC是网页的一块区域,元素基于这块区域布局。创建BFC的元素做出了以下3件事情:

    • 包含了内部所有元素的上下外边距。它们不会跟BFC外面的元素产生外边距折叠
    • 包含了内部所有的浮动元素
    • 不会跟BFC外面的浮动元素重叠

    创建BFC的方式:

    • float: left或right,不为none即可
    • overflow:hidden、auto或scroll,不为visible即可
    • display:inline-block、table-cell、table-caption、flex、inline-flex、grid或inline-grid。拥有这些属性的元素称为块级容器(block container)
    • position:absolute或position: fixed。说明网页的根元素也创建了一个顶级的BFC。

    网格系统

    浮动布局无法轻松地复用样式表中的内容。比如现在媒体对象的宽度是50%,因此一行有两个元素。如果想要复用前面的设计,但需要一行放三个元素,那又该怎么办呢?一种比较普遍的做法是借助网格系统提高代码的可复用性。网格系统提供了一系列的类名,可添加到标记中,将网页的一部分构造成行和列。它只给容器设置宽度和定位。

    大部分流行的CSS框架包含了自己的网格系统。接下来构建一个网格系统,这样你就能掌握它的工作原理,进而应用到网页中。

    CSS框架:一个预编译的CSS代码库,提供了Web开发中常见的样式模式。它能够帮助快速搭建原型或者提供一个稳定的样式基础,辅助构建新样式。常见的框架包括Bootstrap、Foundation以及Pure。


    理解网格系统

    要构建一个网格系统,首先要定义它的行为。通常网格系统的每行被划分为特定数量的列,一般是12个,但也可以是其他数。每行子元素的宽度可能等于1~12个列的宽度。下面代码里的标记直观地展示了网格系统:

    <div class="row">
        <div class="column-4">4 column</div>
        <div class="column-8">8 column</div>
    </div>
    

    构建网格系统

    首先,行元素主要是给列元素提供一个容器,并将其包裹起来。清除浮动恰好能起到这个作用:

    .row::after{
        content:" ";
        display:block;
        clear:both
    }
    

    其次,给列元素添加初始样式。只需将所有的列都浮动到左边,并给每种列元素指定宽度值。可能需要花点时间计算出不同列的宽度百分比,要精确到小数点后几位,以免因为四舍五入而导致误差。

    [class*="column-"] {float: left;}	//属性选择器,匹配包含column-的元素
    
    .column-1 {  8.3333%; }		// 1/12
    .column-2 {  16.6667%; }		// 2/12
    .column-3 {  25%; }			// 3/12等
    .column-4 {  33.3333%; }
    .column-5 {  41.6667%; }
    .column-6 {  50%; }
    .column-7 {  58.3333%; }
    .column-8 {  66.6667%; }
    .column-9 {  75%; }
    .column-10 {  83.3333%; }
    .column-11 {  91.6667% }
    .column-12 {  100%; }
    

    添加间隔

    给每个网格列添加左右内边距,创造间隔。因为需要列之间有1.5em的间隔,所以可以将其分成两半,给每个列元素左右各添加一半的内边距

    [class*="column-"] {
        float: left;
        padding:0 0.75em;	//添加间隔
        margin-top:0		//去除顶部外边距
    }
    

    调整:去掉每行第一列的左侧内边距和最后一列的右侧内边距

    .row{
        margin-left:-0.75em;
        margin-right:-0.75em;
    }
    

    总结

    • 浮动的设计初衷是让文字围绕一个元素排列
    • 使用清除浮动来包含浮动元素
    • BFC有3个好处:包含浮动元素,防止外边距折叠,防止文档流围绕浮动元素排列
    • 使用双容器模式让页面内容居中
    • 使用网格系统实现更丰富的网页布局。

    二、弹性布局

    Flexbox,全称弹性盒子布局(Flexible Box Layout)跟浮动布局相比,Flexbox的可预测性更好,还能提供更精细的控制。它也能轻松解决困扰我们许久的垂直居中和等高列问题。

    原则

    给元素添加display: flex,该元素变成了一个弹性容器,它的直接子元素变成了弹性子元素。下面是三个概念的一些说明:弹性容器、弹性子元素、两条轴:

    • 弹性子元素默认是在同一行按照从左到右的顺序并排排列
    • 弹性容器像块元素一样填满可用宽度
    • 弹性子元素不一定填满其弹性容器的宽度
    • 弹性子元素高度相等,该高度由它们的内容决定
    • 弹性容器能控制内部元素的布局
    • 子元素按照主轴线排列,主轴的方向从左到右。副轴的方向从上到下。可改变

    image.png

    示例

    image.png

    结构

    <div class="container">
        <!-- 标题 -->
        <header>
            <h1>Ink</h1>
        </header>
    
        <!-- 导航菜单 -->
        <nav>
            <ul class="site-nav">
            <li><a href="/">Home</a></li>
            <li><a href="/features">Features</a></li>
            <li><a href="/pricing">Pricing</a></li>
            <li><a href="/support">Support</a></li>
            <li class="nav-right"><a href="/about">About</a></li>
            </ul>
        </nav>
    
        <!-- 主体版块 -->
        <main class="flex">
            <!-- 左侧容器 -->
            <div class="column-main tile">
            <h1>Team collaboration done right</h1>
            <p>Thousands of teams from all over the
                world turn to <b>Ink</b> to communicate
                and get things done.</p>
            </div>
    
            <!-- 右侧容器 -->
            <div class="column-sidebar">  
                <!-- 1.登陆容器 -->
                <div class="tile">
                    <form class="login-form">
                    <h3>Login</h3>
                    <p>
                        <label for="username">Username</label>
                        <input id="username" type="text" name="username"/>
                    </p>
                    <p>
                        <label for="password">Password</label>
                        <input id="password" type="password" name="password"/>
                    </p>
                    <button type="submit">Login</button>
                    </form>
                </div>
    
                <!-- 2.价格容器 -->
                <div class="tile centered">
                    <small>Starting at</small>
                    <div class="cost">
                    <span class="cost-currency">$</span>
                    <span class="cost-dollars">20</span>
                    <span class="cost-cents">.00</span>
                    </div>
                    <a class="cta-button" href="/pricing">
                    Sign up
                    </a>
                </div>
            </div>
        </main>
    </div>
    

    基础样式

    /* 全局设置box-sizing */
    :root{
      box-sizing: border-box;
    }
    *,::before,::after{
      box-sizing: inherit;
    }
    
    /* 设置页面的背景颜色和字体 */
    body{
      background-color: #709b90;
      font-family: Arial, Helvetica, sans-serif;
    }
    
    /* 全局设置外边距 */
    body *+*{
      margin-top: 1.5em;
    }
    
    /* 双容器实现居中 */
    .container{
      max- 1080px;
      margin: 0 auto;
    }
    

    导航菜单

    要实现这个菜单,需要考虑让哪个元素做弹性容器。在本例中,弹性容器应该是<ul>,它的子元素<li>

    .site-nav{
      /*1.给容器加上弹性布局*/
      display: flex;
      background-color: #5f4b44;
        
      /* 2.覆盖列表默认样式 */
      list-style-type: none;
      padding-left: 0;
    }
    
    .site-nav>li{
      /* 3.覆盖猫头鹰顶部外边距 */
      margin-top: 0;
    }
    
    .site-nav>li>a{
      background-color: #cc6b5a;
      color: white;
      text-decoration: none;
    }
    

    旧版浏览器要求给Flexbox属性加上浏览器前缀。比如,旧版Safari浏览器没实现display:flex,而是实现了display:-webkit-flex。需要写成:

    display:-ms-flexbox;	//为了支持旧版IE
    display:-webkit-flex;	//为了支持旧版Safari
    display:flex;
    
    .site-nav{
      ...
      /* padding-left: 0; */
      /* 5.优化容器 给菜单容器加上内边距 */
      padding: .5em;
      border-radius: .2em;
    }
    
    .site-nav>li>a{
      ...
      /* 6.优化连接 让链接变成块级元素,使之撑开父元素高度。并给链接加上内边距 */
      display: block;
      padding: .5em 1em;
    }
    
    /* 7.添加间隔 借鉴猫头鹰选择器。选中除第一个外所有li,为其添加左外边距 */
    .site-nav>li+li{
      margin-left: 1.5em;
    }
    
    /* 8.修改按钮位置 利用弹性盒子的特性,把外边距设置为auto,使其填充所有可用空间 */
    .site-nav>.nav-right{
      margin-left: auto;
    }
    

    image.png

    flex设置大小

    可以用width和height属性设置它们大小Flexbox提供了更多更强大的选项——flex。flex属性控制弹性子元素在主轴方向上的大小。在该例中给网页的主区域应用弹性布局,并使用flex属性控制每一列的大小。首先先完成基础样式部分:

    /* 1.将主容器设置为弹性布局 */
    .flex{
      display: flex;
    }
    
    /* 2.给三个板块加上白色背景和内边距 */
    .tile{
      padding: 1.5em;
      background-color: #fff;
    }
    
    /* 3.去掉右侧容器的顶部外边距,并给每个子元素加上间隔*/
    .flex>*+*{
      margin-top: 0;
      margin-left: 1.5em;
    }
    

    image.png

    目前还没有特别设置两列的宽度,所以是根据内容自适应的宽度。可见没有完全填满可用空间。本例用column-main和column-sidebar类来指定两列,现在使用flex属性给两列分别赋以2/3和1/3的宽度:

    .column-main{
      flex: 2;
    }
    .column-sidebar{
      flex: 1;
    }
    


    flex属性是三个不同大小属性的简写:flex-grow、flex-shrink和flex-basis。你也可以分别声明三个属性。接下来看看三个属性分别表示什么:

    flex-grow:1;
    flex-shrink:1;
    flex-basis:0%
    
    flex-grow:2;
    flex-shrink:1;
    flex-basis:0%
    
    • flex-basis:定义了元素大小的基准值,即一个初始的“主尺寸”。可以设置为任意的width值,包括px、em、百分比,它的初始值是auto。

      每个弹性子元素的flex-basis值计算出来后,它们(加上子元素之间的外边距)加起来会占据一定的宽度。加起来的宽度不一定正好填满弹性容器的宽度,可能会有留白,如下图:

      image.png

      每个弹性子元素的初始主尺寸确定后,它们可能需要在主轴方向扩大或者缩小来适应(或者填充)弹性容器的大小。对于上面的情况,可能需要flex-grow和flex-shrink来决定缩放的规则。

    • flex-grow:增长因子。多出来的留白会按照flex-grow的值分配给每个弹性子元素,值为非负整数。如果一个弹性子元素的flex-grow值为0,那么它的宽度不会超过flex-basis的值;如果某个弹性子元素的增长因子非0,那么这些元素会增长到所有的剩余空间被分配完,也就意味着弹性子元素会填满容器的宽度

      image.png

      flex-grow的值越大,元素的“权重”越高,也就会占据更大的剩余宽度:

      image.png

    • flex-shrink:防止溢出。计算出弹性子元素的初始主尺寸后,它们的累加值可能会超出弹性容器的可用宽度。如果不用flex-shrink,就会导致溢出

      image.png

      每个子元素的flex-shrink值代表了它是否应该收缩以防止溢出。如果某个子元素为flex-shrink: 0,则不会收缩;如果值大于0,则会收缩至不再溢出。按照flex-shrink值的比例,值越大的元素收缩得越多。


    实际应用

    image.png

    弹性方向

    弹性布局的另一个重要功能是能够切换主副轴方向,用弹性容器的flex-direction属性控制。如前面的例子,它的初始值是row

    image.png

    现在的布局有一个隐藏的缺陷,给主板块添加更多内容,会发现主板块超出了右边板块的底部。Flexbox应该能让两列的高度相等,为什么不起作用了呢?

    image.png

    其实左右两个弹性子元素是等高的。问题是右边栏内部的两个板块没有扩展到填满右边栏区域。如果想让两列扩展到填满容器的高度。要将右边栏(column-sidebar)改为弹性容器,并设置flex-direction: column。然后给里面的两个板块设置非0的flex-grow值:

    .column-sidebar{
      flex: 1;
      /* 1.对右侧容器设置弹性布局与弹性方向 此时它对外来说是弹性子元素,对内来说是弹性容器*/
      display: flex;
      flex-direction: column;
    }
    
    .column-sidebar>.tile{
      /* 2.给右侧容器的子元素加上flex-grow */
      flex: 1;
    }
    

    内部的弹性盒子的弹性方向为column,表示主轴发生了旋转,现在变成了从上到下。现在对于弹性子元素而言,flex-basis、flex-grow和flex-shrink现在作用于元素的高度而不是宽度。

    说明:水平弹性盒子与垂直的弹性盒子有一点不同:水平弹性容器会占据100%的可用宽度,而高度则由自身的内容来决定。在垂直的弹性盒子里,子元素的flex-grow和flex-shrink不会起作用


    完善登陆表单

    /* 标题设置加粗、右对齐、全大写 */
    .login-form h3{
      margin: 0;
      font-size: .9em;
      font-weight: bold;
      text-align: right;
      text-transform: uppercase;
    }
    
    /* 给输入框添加样式 */
    .login-form input{
      display: block;
       100%;
      margin-top: 0;
    }
    
    .login-form button{
      margin-top: 1em;
      /* 覆盖按钮默认样式 */
      border: 1px solid#cc6b5a;
      background-color: white;
      padding: .5em 1em;
      cursor: pointer;
    }
    

    弹性容器属性

    flex-direction 指定了主轴方向,副轴垂直于主轴
    row 主轴从左到右
    row-reverse 主轴从右到左
    column 主轴从上到下
    column-reverse 主轴从下到上
    flex-wrap 是否允许弹性子元素在弹性容器内折行/列显示
    允许后,子元素不再根据flex-shrink值收缩
    nowrap 不允许
    wrap 折行
    wrap-reverse 折行且从末尾开始排列
    flex-flow flex-direction和flex-wrap的简写
    justify-content 控制子元素在主轴上的位置
    任意子元素的flex-grow的值不为0,
    或者任意子元素在主轴方向的外边距值为auto
    该属性失效
    flex-start image.png
    flex-end image.png
    center image.png
    space-between image.png
    space-around image.png
    align-items 控制子元素在副轴上的位置
    flex-start image.png
    flex-end image.png
    center image.png
    stretch(初始) image.png
    baseline image.png
    align-content 如果开启了flex-wrap,align-content就会控制
    弹性子元素在副轴上的间距。
    如果子元素没有换行,会忽略该属性
    flex-start image.png
    flex-end image.png
    center image.png
    stretch image.png
    space-between image.png
    space-around image.png

    弹性子元素的属性

    flex-grow 指定“增长因子”,填充未使用空间 image.png
    flex-shrink 指定“收缩因子”,防止溢出
    如果弹性容器开启了flex-wrap,则会忽略该属性
    image.png
    flex-basis 指定子元素初始大小
    flex flex-grow、flex-shrink、shrink的缩写
    align-self 控制子元素在副轴上的对齐方式
    会覆盖容器上的align-items值
    若元素副轴方向上的外边距为auto,则忽略
    auto image.png
    flex-start image.png
    flex-end image.png
    center image.png
    stretch image.png
    baseline image.png
    Order 整数,将子元素从兄弟节点中移动到指定位置,覆盖源码顺序

    完善示例

    接下来使用以上介绍的一些属性来完成网页最后一个板块:

    解析:文字$20.00被包裹在<div class="cost">中。该元素将作为弹性容器,它有三个弹性子元素,放置三个需要对齐的文字部分:$、20、.00

    /* 给容器设置文本居中 */
    .centered{
      text-align: center;
    }
    
    /* 给文字容器设置弹性布局 */
    /* 指定子元素在主轴和副轴上居中排列 */
    .cost{
      display: flex;
      justify-content: center;
      align-items: center;
      line-height: .7;
    }
    
    /* 覆盖猫头鹰选择器的外边距 */
    .cost>span{
      margin-top: 0;
    }
    
    .cost-currency{
      font-size: 2rem;
    }
    .cost-dollars{
      font-size: 4rem;
    }
    /* 覆盖子元素的align-items,单独改变子元素排列方式,改成顶部对齐而不是垂直居中 */
    .cost-cents{
      font-size: 1.5rem;
      align-self: flex-start;
    }
    
    .cta-button{
      display: block;
      background-color: #cc6b5a;
      color: #fff;
      padding: .5em 1em;
      text-decoration: none;
    }
    

    三、网格布局

    引入

    CSS网格可以定义由行和列组成的二维布局,然后将元素放置到网格中。网格的大小既可以精确定义,也可以根据自身内容自动计算。可以将元素精确地放置到网格某个位置,也可以让其在网格内自动定位,填充划分好的区域。

    image.png

    与弹性布局对比,浏览器实现弹性布局的早期版本时,加浏览器前缀才能使用。随着规范的演变,浏览器更新了实现方式,开发人员也必须相应地更新自己的代码,但是还要将以前的代码保留以支持旧版的浏览器,这导致Flexbox问世的经历十分坎坷。与此同时,浏览器几乎可以完全实现网格布局。

    构建基础网格

    现在先创建一个简单的网格布局,以确认浏览器支持该特性。跟Flexbox类似,网格布局也是作用于两级的DOM结构。设置为display: grid的元素成为一个网格容器,它的子元素则变成网格元素

    image.png

    <div class="grid">
        <div class="a"></div>
        <div class="b"></div>
        <div class="c"></div>
        <div class="d"></div>
        <div class="e"></div>
        <div class="f"></div>
    </div>
    

    样式部分

    .grid{
      display: grid;                        /* 1.设置网格布局 */
      grid-template-columns: 1fr 1fr 1fr;   /* 2.定义等宽三列 */
      grid-template-rows: 1fr 1fr;          /* 3.定义等高两行 */
      grid-gap: 0.5em;                      /* 4.单元格间距 */
    }
    
    .grid>*{
      background-color: #eee;
      color: white;
      padding: 2em;
      border-radius: 0.5em;
    }
    
    • display: grid:定义网格容器。容器会表现得像一个块级元素,100%填充可用宽度

    • grid-template-columns:定义了网格每列大小

    • grid-template-rows:定义了网格每行大小

    • fr:分数单位。这里也可以使用其他单位。例如:grid-template-columns: 300px 1fr定义了一个固定宽度为300px的列,后面跟着一个会填满剩余可用空间的列

    • grid-gap:定义了每个网格单元之间的间距。也可以用两个值分别指定垂直和水平方向的间距,比如:grid-gap: 0.5em 1em

    网格剖析

    1. 四个概念

    前面提及了网格布局的两个基本元素:网格容器和网格元素。下面是另外四个重要概念:

    image.png

    • 网格线——网格线构成了网格的框架
    • 网格轨道——一个网格轨道是两条相邻网格线之间的空间。网格有水平轨道(行)和垂直轨道(列)
    • 网格单元——网格上的单个空间,水平和垂直的网格轨道交叉重叠的部分
    • 网格区域——网格上的矩形区域,由一个到多个网格单元组成。

    2. 示例

    如果用网格布局实现之前的示例会是怎样?在下图中,虚线标出了每个网格单元的位置。注意,某些部分跨越了好几个网格单元:

    image.png

    现在,用网格实现弹性布局示例需要改一下HTML结构。这个版本的HTML将网页的所有部分都变成了网格元素:头部、菜单(nav)、主区域,还有两个侧边栏。主区域和两个侧边栏都加上了类tile,用来指定元素共有的白色背景和内边距:

    <!-- 网格容器 -->
    <div class="container">
    
        <!-- 每个网格元素必须是网格容器的子元素 -->
        <header>
            <h1 class="page-heading">Ink</h1>
        </header>
        
        <nav>
            <ul class="site-nav">
            <li><a href="/">Home</a></li>
            <li><a href="/features">Features</a></li>
            <li><a href="/pricing">Pricing</a></li>
            <li><a href="/support">Support</a></li>
            <li class="nav-right">
                <a href="/about">About</a>
            </li>
            </ul>
        </nav>
        
        <main class="main tile">
            <h1>Team collaboration done right</h1>
            <p>Thousands of teams from all over the
            world turn to <b>Ink</b> to communicate
            and get things done.</p>
        </main>
    
        <div class="sidebar-top tile">
            <form class="login-form">
            <h3>Login</h3>
            <p>
                <label for="username">Username</label>
                <input id="username" type="text"
                name="username"/>
            </p>
            <p>
                <label for="password">Password</label>
                <input id="password" type="password"
                name="password"/>
            </p>
            <button type="submit">Login</button>
            </form>
        </div>
    
        <div class="sidebar-bottom tile centered">
            <small>Starting at</small>
            <div class="cost">
                <span class="cost-currency">$</span>
                <span class="cost-dollars">20</span>
                <span class="cost-cents">.00</span>
            </div>
            <a class="cta-button" href="/pricing">Sign up</a>
        </div>
    </div>
    

    样式

    :root{
      box-sizing: border-box;
    }
    *,::before,::after{
      box-sizing: inherit;
    }
    body{
      background-color: #709b90;
      font-family: Arial, Helvetica, sans-serif;
    }
    
    
    .container{
      display: grid;                      /* 定义网格布局 */
      grid-template-columns: 2fr 1fr;     /* 定义两个垂直网络轨道 */
      grid-template-rows: repeat(4,auto); /* 定义四个水平规定 大小为auto */
      gap: 1.5em;                         
    
      max- 1080px;
      margin: 0 auto;
    }
    
    /* 网格元素定位*/
    header,nav{
        grid-column:1/3;
        grid-row:span 1
    }
    
    .main{
      grid-column: 1/2;
      grid-row: 3/5;
    }
    .sidebar-top{
      grid-column: 2/3;
      grid-row: 3/4;
    }
    .sidebar-bottom{
      grid-column: 2/3;
      grid-row: 4/5;
    }
    
    
    .tile{
      padding: 1.5em;
      background-color: white;
    }
    .tile>:first-child{
      margin-top: 0;
    }
    .tile *+*{
      margin-top: 1.5em;
    }
    
    • repeat():声明多个网格轨道的时候提供了简写方式。

      比如上面的grid-template-rows: repeat(4, auto)定义了四个水平网格轨道,高度为auto,这等价于grid-template-rows: auto auto auto auto。轨道大小设置为auto,轨道会根据自身内容扩展。

      repeat()符号还可以定义不同的重复模式,比如repeat(3, 2fr1fr)会重复三遍这个模式,从而定义六个网格轨道,重复的结果是2fr 1fr 2fr 1fr 2fr 1fr

    定位-网格线编号

    image.png

    • grid-column:用列网格线的编号指定网格元素的位置

    • grid-row:用列网格线的编号指定网格元素的位置

      比如,想要一个网格元素在垂直方向上从1号网格线跨越到3号网格线:grid-column: 1 / 3

      这些属性实际上是简写属性:grid-columngrid-column-startgrid-column-end的简写;grid-rowgrid-row-startgrid-row-end的简写。中间的斜线只在简写属性里用于区分两个值


      网格线编号+span

      除了使用1/2跨越网格线,还可以使用span 1,span表示要跨越几行。如果前面没有指出哪一行,浏览器会根据网格元素的布局算法自动将其放到合适的位置。如果前面加上了网格线编号,它会从指定行开始跨越网格轨道:

      //从第三条网格线跨到第五条网格线:
      grid-row: 3/5;  
      
      //span写法。表示从第三条网格线开始,跨两个网络轨道
      grid-row: 3/span 2;
      

    与Flexbox配合

    弹性布局和网格布局是互补的,它们各自擅长的场景不一样。这两种布局方式有以下两个重要区别:

    • Flexbox本质上是一维的,而网格是二维的
    • Flexbox是以内容为切入点由内向外工作的,而网格是以布局为切入点从外向内工作的

    因为Flexbox是一维的,所以它很适合用在相似的元素组成的行或列上,它支持换行但是没法让上一行元素跟下一行元素对齐。相反,网格是二维的,旨在解决一个轨道的元素跟另一个轨道的元素对齐的问题:

    image.png

    替代语法

    1.命名网格线

    记编号也许会乱,这时可以给网格线命名。下面声明定义了两列的网格,三条垂直的网格线分别叫作start、center和end:

    grid-template-columns:[start] 2fr [center] 1fr [end]
    grid-column:start/center //使用
    
    • 给同一个网格线提供多个名称

      grid-template-columns:[left-start] 2fr [left-end right-start] 1fr [right-end]
      

    将网格线命名为left-start和left-end,就定义了一个叫作left的区域-start-end后缀作为关键字,定义了两者之间的区域。如果给元素设置grid-column: left,它就会跨越从left-start到left-end的区域

    • 以各种方式命名的网格线

      比如,将两个网格列列为一组,在每组之前命名一条网格线:

      image.png

      grid-template-columns: repeat(3, [col] 1fr 1fr) //命名
      grid-column: col 2 /span 2						//使用,定位在第二组
      

    2.命名网格区域

    除了命名网格线,可以直接用命名网格区域将元素定位到网格中。实现这一方法需要借助下面两个属性:

    • grid-template(网格容器属性)
    • grid-area(网格元素属性)
    .container{
      display: grid;
      /* 1.给每个网格单位命名*/
      grid-template-areas: "title title"
                           "nav nav"
                           "main aside1"
                           "main aside2";                  
      grid-template-columns: 2fr 1fr;     
      grid-template-rows: repeat(4,auto); 
      gap: 1.5em;                         
      max- 1080px;
      margin: 0 auto;
    }
    
    /* 2.将每个网格元素放进一个命名的网格区域 */
    header{
      grid-area: title;
    }
    nav{
      grid-area: nav;
    }
    .main{
      grid-area: main;
    }
    .sidebar-top{
      grid-area: aside1;
    
    }
    .sidebar-bottom{
      grid-area: aside2;
    }
    

    注意:每个命名的网格区域必须组成一个矩形。

    用句点(.)作为名称空出一个网格单元

    grid-template-areas: "top top right"
                		 "left . right"
                		 "left bottom bottom" 
    

    总结

    当构建一个网格时,选择一种舒适的语法即可。网格布局共设计了三种语法:编号的网格线、命名的网格线、命名的网格区域

    隐式网格

    在某些场景下,你可能不清楚该把元素放在网格的哪个位置上,比如当元素是从数据库获取时。在这些情况下,以一种宽松的方式定义网格更合理。

    这时需要用到隐式网格。使用grid-template-*属性定义网格轨道时,创建的是显式网格。而当网格元素放在显式轨道外,会自动创建隐式轨道以扩展网格,从而包含这些元素


    指定大小

    • grid-auto-columns:指定隐性网络列大小(隐式网格轨道默认大小为auto,会扩展到能容纳网格元素内容)

    • grid-auto-rows:指定隐性网络行大小

    比如在这个布局中,显性创建列的网格轨道,隐性创建行的网格轨道。这样它能适应任意数量的网格元素。只要照片需要换行显示,就会隐式创建新的一行:

    image.png

    html结构:portfolio网格容器包括网格元素figure,网格元素figure下是一张图与标题。其中featured类来通过跨行跨列来改变图片大小

    <div class="portfolio">
        <figure class="featured">
            <img src="images/01.jpg" alt="monkey" />
            <figcaption>Monkey</figcaption>
        </figure>
        <figure>
            <img src="images/02.jpg" alt="eagle" />
            <figcaption>Eagle</figcaption>
        </figure>
        <figure class="featured">
            <img src="images/03.jpg" alt="bird" />
            <figcaption>Bird</figcaption>
        </figure>
        <figure>
            <img src="images/04.jpg" alt="bear" />
            <figcaption>Bear</figcaption>
        </figure>
        <figure class="featured">
            <img src="images/05.jpg" alt="swan" />
            <figcaption>Swan</figcaption>
        </figure>
        <figure>
            <img src="images/06.jpg" alt="elephants" />
            <figcaption>Elephants</figcaption>
        </figure>
    </div>
    

    样式

    :root {
      box-sizing: border-box;
    }
    *,
    ::before,
    ::after {
      box-sizing: inherit;
    }
    body {
      background-color: #709b90;
      font-family: Helvetica, Arial, sans-serif;
    }
    
    
    .portfolio {
      display: grid;
      /* 1.显式创建 将最小列宽设置为300px,自动填充网格 */
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));   
      /* 2.隐式创建 将水平网格轨道的大小设置为1fr 即整个容器 */
      grid-auto-rows: 1fr; 
      grid-gap: 1em;
    }
    
    .portfolio .featured{
      /*3.放大内容容器,跨两行和两列。目的是为了在后面让图片撑开*/
      grid-row: span 2;     
      grid-column: span 2;
    }
    
    .portfolio > figure {
      /*4.覆盖默认外边距*/
      margin: 0;        
    }
    
    .portfolio figcaption {
      padding: 0.3em 0.8em;
      background-color: rgba(0, 0, 0, 0.5);
      color: #fff;
      text-align: right;
    }
    
    • minmax():指定最小尺寸和最大尺寸。浏览器会确保网格轨道的大小介于这两者之间

    • auto-fill:这个关键词表示只要网格放得下,浏览器就会尽可能多地生成轨道。如果网格元素不够填满所有网格轨道,auto-fill就会导致一些空的网格轨道


    打开控制台,目前的布局如下。可见目前仍有一些网格没有占据元素被空了出来。这时需要用到下面的属性:

    image.png

    指定布局算法

    • grid-auto-flow:默认情况下,布局算法会按元素在标记中的顺序将其逐列逐行摆放,而这个属性可以控制布局算法的行为。初始值是row,下面的代码使用了grid-auto-flow: dense,等价于grid-auto-flow: row dense

      .portfolio {
        ...
        grid-auto-flow: dense;  /*隐式 开启紧凑的网络布局算法*/
      }
      

      这时布局如下,空出来的网格已经被元素填上去了。然而此时图片并没有填满网格轨道,这时需要用到下面的方法:

      image.png

    网格元素填满网格轨道

    • Flexbox

      默认情况下,每个网格元素都会扩展并填满整个网格区域,但是子元素不会,因此网格区域出现了多余的高度。一个简单的解决办法是用Flexbox,设置每个<figure>为弹性容器,方向为column,元素会从上到下垂直排列。然后给图片标签加上flex-grow,强制拉伸图片填充空白区域:

      .portfolio > figure {
      margin: 0;        
      display: flex;			/*设置弹性布局*/
      flex-direction: column;	/*设置弹性方向*/
      }
      
      .portfolio > figure>img {
      flex-grow: 1;			/*弹性元素拉伸*/
      max- 100%;		/*图片最大只能填满空间*/
      }
      

      image.png

    • object-fit

      但是拉伸图片会改变图片的宽高比,可能会导致图片变形。这时可以用到特殊属性object-fit。默认情况下,<img>的object-fit属性值为fill,也就是整个图片会缩放以填满<img>元素。你也可以设置其他值改变默认行为:

      1. fill(默认)

      2. cover:扩展图片让它填满盒子,导致图片一部分被裁剪

      3. contain:缩放图片让它完整填充盒子,导致盒子里出现空白

      image.png

      .portfolio > figure>img {
        ...
        object-fit: cover;
      }
      

    特性查询

    @supports规则后面跟着一个小括号包围的声明。如果浏览器理解这个声明,它就会使用大括号里面的所有样式规则。如果它不理解小括号里的声明,就不会使用这些样式规则:

    @supports(display:grid){
        ...样式
    }
    
    • @supports not(<declaration>)——只有当不支持查询声明里的特性时才使用里面的样式规则
    • @supports (<declaration>) or (<declaration>)——查询声明里的两个特性只要有一个支持就使用里面的样式规则
    • @supports (<declaration>) and (<declaration>)——查询声明里的两个特性都支持才使用里面的样式规则。

    对齐

    网格布局模块规范里的对齐属性有一些跟弹性布局相同,还有一些是新属性。CSS给网格布局提供了三个水平方向调整属性justify-contentjustify-itemsjustify-self;还有三个垂直方向对齐属性align-contentalign-itemsalign-self

    image.png

    举个例子:它指定了网格容器的高度为1200px,定义了高800px的有效水平网格轨道。

    .grid{
        display:grid;
        height:1200px;
        grid-template-row:repeat(4,200px)
    }
    

    在这里,align-content属性可以指定网格轨道如何在剩下的400px空间内分布,它具有以下值:

    • start——将网格轨道放到网格容器的上/左(Flexbox里则是flex-start)
    • end——将网格轨道放在网格容器的下/右(Flexbox里则是flex-end)
    • center——将网格轨道放在网格容器的中间
    • stretch——将网格轨道拉伸至填满网格容器
    • space-between——将剩余空间平均分配到每个网格轨道之间(它能覆盖任何grid-gap值)
    • space-around——将空间分配到每个网格轨道之间,且在两端各加上一半的间距
    • space-evenly——将空间分配到每个网格轨道之间,且在两端各加上同等大小的间距(Flexbox规范不支持)

    四、定位和上下叠层

    position属性可以用来构建下拉菜单、模态框以及现代Web应用程序的一些基本效果。层叠上下文是定位的一个隐藏的副作用

    1.静态定位

    position:static是默认定位(静态定位),前面所用的都是这个。而如果元素使用了静态定位,那么就说它未被定位

    2.固定定位

    position: fixed让元素相对视口定位,搭配四种属性top、right、bottom和left。这四个值还隐式地定义了元素的宽高。比如指定left: 2em; right: 2em表示元素的左边缘距离视口左边2em,右边缘距离视口右边2em

    示例-创建模态框

    <body>
        <!-- 1.触发弹框的按钮 -->
        <button id="open">打开模态框</button>
        <!-- 2.模态框容器 -->
        <div class="modal" id="modal">   
            <!-- 3.蒙层    -->
            <div class="modal-backdrop"></div>
            <!-- 4.模态框容器 -->
            <div class="modal-body">
                <!-- 5.关闭弹框按钮 -->
                <button id="close" class="modal-close">close</button>
                <p>1111111111111111</p>
                <p>22222222222222</p>
            </div>
        </div>
    </body>
    
    <script type="text/javascript">
        var openModal = document.getElementById('open');
        var closeModal = document.getElementById('close');
        var modal = document.getElementById('modal');
    
        openModal.addEventListener('click', function(event) {
            event.preventDefault();
            modal.style.display = 'block';
        });
    
        closeModal.addEventListener('click', function(event) {
            event.preventDefault();
            modal.style.display = 'none';
        });
    </script>
    

    样式

    body {
      min-height: 200vh;  /* 设置网页高度,让页面出现滚动条(为了体现固定定位) */
      margin: 0;
    }
    
    button {
      padding: .5em .7em;
      border: 1px solid #8d8d8d;
      background-color: white;
      font-size: 1em;
    }
    
    .modal {
      display: none;
    }
    
    /* 蒙层:当打开模态框时,用半透明的蒙层遮挡网页剩余内容 */
    .modal-backdrop {
      position: fixed;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      background-color: rgba(0, 0, 0, 0.5);
    }
    
    /* 模态框定位 */
    .modal-body {
      position: fixed;
      top: 3em;
      bottom: 3em;
      right: 20%;
      left: 20%;
      padding: 2em 3em;
      background-color: white;
      overflow: auto;
    }
    

    因为固定元素从文档流中移除了,所以它不影响页面其他元素的位置。别的元素跟随正常文档流,就像固定元素不存在一样。

    控制定位元素的大小

    • 指定四个方向的值

      position: fixed;
      top: 3em;
      bottom: 3em;
      right: 20%;
      left: 20%;
      
    • 指定需要的方向值并用width和/或height

      position:fixed
      top:1em;
      right:1em;
      20%
      

    3.绝对定位

    position: absolute相对最近的祖先定位元素。配合top、right、bottom和left定义元素位置

    示例-close按钮

    现在将Close按钮放在模态框的右上角。

    .modal-close {
      position:absolute;
      top: 0.3em;
      right: 0.3em;
      padding: 0.3em;
    }
    

    相对于谁,我们就把谁叫做包含块。在本例中,包含块是它的父元素。如果父元素未被定位,那么浏览器会沿着DOM树往上找它的祖父、曾祖父,直到找到一个定位元素。如果祖先元素都没有定位,那么绝对定位的元素会基于初始包含块来定位,初始包含块跟视口一样大,固定在网页的顶部。

    定位伪元素

    对于关闭按钮,用户通常期望看到一个类似于x的图形化显示。这时可以用CSS隐藏close,并显示x。

    • 将按钮的文字挤到外面,隐藏溢出内容
    • 将按钮的::after伪元素的content属性设置为x,并让伪元素绝对定位到按钮中间
    .modal-close {
      ...
      font-size: 2em;
      height: 1em;         /* 1.让按钮变成小正方形 目的是为了挤出文字*/
       1em;
      text-indent: 10em;  /* 2.挤出文字并隐藏溢出 */
      overflow: hidden;
      border: 0;
    }
    .modal-close::after{
      position: absolute;	/*3.按钮成为伪元素的包含块*/
      line-height: 0.5;	/* 4.设置一个较小的line-height让伪元素不要太高 */
      top: 0.2em;		/*5.位置需要自己反复调整*/
      left: 0.1em;
      text-indent: 0;
      content: "0D7";  /* 6.添加Unicode字符U+00D7(乘法符号) */
      cursor: pointer;
    }
    

    最后呈现:

    image.png

    4.相对定位

    应用position: relative通常看不到页面有视觉改变。如果加上top、right、bottom和left属性,元素会移走,但是不会改变它周围任何元素的位置。有时可以用这些属性调整相对元素的位置,把它挤到某个位置,但这只是相对定位的一个冷门用法。更常见的用法是使用position: relative给它里面的绝对定位元素创建一个包含块。

    示例-创建下拉菜单

    html结构

    <!-- 1.下拉菜单容器 -->
    <div class="dropdown">
        <div class="dropdown-label">Main Menu</div>
        <!-- 2.菜单列表容器 -->
        <div class="dropdown-menu">
            <ul class="submenu">
            <li><a href="/">Home</a></li>
            <li><a href="/coffees">Coffees</a></li>
            <li><a href="/brewers">Brewers</a></li>
            <li><a href="/specials">Specials</a></li>
            <li><a href="/about">About us</a></li>
            </ul>
        </div>
    </div>
    

    样式

    .dropdown {
      display: inline-block;
      position: relative;     /*1.创建包含块*/
    }
    .dropdown-label {
      padding: 0.5em 1.5em;
      border: 1px solid #ccc;
      background-color: #eee;
      cursor: pointer;
    }
    
    .dropdown-menu {
      display: none;  /*2.隐藏菜单列表*/
      position: absolute;
      left: 0;
      top: 2.1em;   /*3.将菜单列表移到菜单下面 内边距+字体大小+边框*/
      min- 100%;
      background-color: #eee;
    }
    
    /*4.鼠标悬浮展示菜单列表*/
    .dropdown:hover .dropdown-menu{
      display: block;
    }
    
    .submenu {
      padding-left: 0;
      margin: 0;
      list-style-type: none;
      border: 1px solid #999;
    }
    
    .submenu > li + li {
      border-top: 1px solid #999;
    }
    
    .submenu > li > a {
      display: block;
      padding: 0.5em 1.5em;
      background-color: #eee;
      color: #369;
      text-decoration: none;
    }
    
    .submenu > li > a:hover {
      background-color: #fff;
    }
    

    示例-创建CSS三角形

    下拉菜单距离完美还差一步。可以用边框画一个三角形当作向下箭头。这里用标签的::after伪元素来画三角形,然后使用绝对定位将它放到标签的右边。

    原理

    粗边框如下:

    image.png

    将元素的宽和高缩小到0:

    image.png

    保留顶部边框,其他设置为透明:

    image.png
    实现:

    .dropdown-label {
      ...
      /* css三角形-增加右侧内边距,给箭头留出空间 */
      padding: 0.5em 2em 0.5em 1.5em;
    }
    
    /* css三角形-添加伪元素 */
    .dropdown-label::after {
      content: "";
      position: absolute;
      right: 1em;
      top: 1em;
      border: 0.3em solid;
      border-color: black transparent transparent;
    }
    /* css三角形-翻转 */
    .dropdown:hover .dropdown-label::after {
      top: 0.7em;
      border-color: transparent transparent black;
    }
    

    5.层叠上下文

    在同一页面定位多个元素时,可能会遇到两个不同定位的元素重叠的现象。

    渲染过程与层叠顺序

    浏览器将HTML解析为DOM的同时还创建了另一个树形结构,叫作渲染树(render tree)。它代表了每个元素的视觉样式和位置。同时还决定浏览器绘制元素的顺序。

    • 未使用定位时,元素在HTML里出现的顺序决定了绘制的顺序,后出现的元素会绘制在先出现的元素前面
    • 使用定位时,浏览器会先绘制所有非定位的元素,然后绘制定位元素。即默认情况下,定位元素会出现在非定位元素前

    z-index控制层叠顺序

    z-index的值越高,表示越在前。使用它时需要注意以下两点:

    • z-index只在定位元素上生效,不能用它控制静态元素
    • 给一个定位元素加上z-index可以创建层叠上下文

    层叠上下文

    一个层叠上下文包含一个元素或者由浏览器一起绘制的一组元素。其中一个元素会作为层叠上下文的根,比如给一个定位元素加上z-index的时候,它就变成了一个新的层叠上下文的根。所有后代元素就是这个层叠上下文的一部分。

    层叠上下文内的元素会按照以下顺序从后到前叠放

    • 层叠上下文的根
    • z-index为负的定位元素(及其子元素)
    • 非定位元素
    • z-index为auto的定位元素(及其子元素)
    • z-index为正的定位元素(及其子元素)

    6.粘性定位

    position:sticky粘性定位是相对定位和固定定位的结合体:正常情况下,元素会随着页面滚动,当到达屏幕的特定位置时,如果用户继续滚动,它就会“锁定”在这个位置。最常见的用例是侧边栏导航。

    五、响应式设计

    原则一 移动优先

    构建桌面版之前要先构建移动端布局,确保两个版本都生效。这是因为移动端的限制更多,如果先设计pc端,那么有些效果可能不会在移动端生效

    移动端关注内容,其他地方可以隐藏或者放在不起眼的地方

    断点:一个特殊的临界值。屏幕尺寸达到这个值时,网页的样式会发生改变,以便给当前屏幕尺寸提供最佳的布局。

    示例-起步

    <header id="header" class="page-header">
        <div class="title">
            <h1>Wombat Coffee Roasters</h1>
            <div class="slogan">We love coffee</div>
        </div>
    </header>
    
    <!-- 菜单 -->
    <nav class="menu" id="main-menu">
    <button class="menu-toggle" id="toggle-menu">
        toggle menu
    </button>
    <div class="menu-dropdown">
        <ul class="nav-menu">
        <li><a href="/about.html">About</a></li>
        <li><a href="/shop.html">Shop</a></li>
        <li><a href="/menu.html">Menu</a></li>
        <li><a href="/brew.html">Brew</a></li>
        </ul>
    </div>
    </nav>
    
    <!-- 主图 -->
    <aside id="hero" class="hero">
        Welcome to Wombat Coffee Roasters! We are
        passionate about our craft, striving to bring you
        the best hand-crafted coffee in the city.
    </aside>
    
    <!-- 主体内容 -->
    <main id="main">
        <div class="row">
            <section class="column">
            <h2 class="subtitle">Single-origin</h2>
            <p>We have built partnerships with small farms
                around the world to hand-select beans at the
                peak of season. We then carefully roast in
                <a href="/batch-size.html">small batches</a>
                to maximize their potential.</p>
            </section>
    
            <section class="column">
            <h2 class="subtitle">Blends</h2>
            <p>Our tasters have put together a selection of
                carefully balanced blends. Our famous
                <a href="/house-blend.html">house blend</a>
                is available year round.</p>
            </section>
            
            <section class="column">
            <h2 class="subtitle">Brewing Equipment</h2>
            <p>We offer our favorite kettles, French
                presses, and pour-over cones. Come to one of
                our <a href="/classes.html">brewing
                classes</a> to learn how to brew the perfect
                pour-over cup.</p>
            </section>
        </div>
    </main>
    

    css

    /* 基础样式*/
    :root {
      box-sizing: border-box;
      /* 字体大小根据视口适当缩放 */
      font-size: calc(1vw + 0.6em);
    }
    *,*::before,*::after {
      box-sizing: inherit;
    }
    body {
      margin: 0;
      font-family: Helvetica, Arial, sans-serif;
    }
    
    /* 链接 */
    a:link {
      color: #1476b8;
      font-weight: bold;
      text-decoration: none;
    }
    a:visited {
      color: #1430b8;
    }
    a:hover {
      text-decoration: underline;
    }
    a:active {
      color: #b81414;
    }
    
    
    /* 网页头部和标题 */
    .page-header {
      padding: 0.4em 1em;
      background-color: #fff;
    }
    .title > h1 {
      color: #333;
      text-transform: uppercase;
      font-size: 1.5rem;
      margin: .2em 0;
    }
    .slogan {
      color: #888;
      font-size: 0.875em;
      margin: 0;
    }
    
    
     /*Hero image */
    .hero {
      padding: 2em 1em;
      text-align: center;
      background-image: url(images/01.jpeg);
      background-size: 100%;
      color: #fff;
      text-shadow: 0.1em 0.1em 0.3em #000;
    }
    
    /* 主体内容 */
     main {
       padding: 1em;
     }
    
    .subtitle {
      margin-top: 1.5em;
      margin-bottom: 1.5em;
      font-size: 0.875rem;
      text-transform: uppercase;
    }
    

    效果如图:

    image.png

    示例-创建菜单

    汉堡包菜单:它解决了在小屏幕里显示更多内容的问题,但是也有弊端。将重要元素(比如主要的导航菜单)隐藏起来会减少用户跟它们交互的机会

    image.png

    /* 汉堡包菜单 */
    .menu {
      position: relative; /*1.创建包含块*/
    }
    .menu-toggle {
      position: absolute;
      top: -1.2em;    /*2.将按钮拉到包含块上面*/
      right: 0.1em;
      border: 0;      /*3.覆盖浏览器按钮样式*/
      background-color: transparent;
      font-size: 3em;
      line-height: 0.4;
      text-indent: 5em;  /*4.隐藏按钮的文本*/
       1em;
      height: 1em;
      overflow: hidden;
      white-space: nowrap;
    }
    .menu-toggle::after {
      position: absolute;
      top: 0.2em;
      left: 0.2em;
      display: block;
      content: "2261";   /*5.汉堡包图标*/
      text-indent: 0;
    }
    .menu-dropdown {
      display: none;
      position: absolute;
      right: 0;
      left: 0;
      margin: 0;
    }
    .menu.is-open .menu-dropdown {
      display: block;   /*6.当加上is-open类的时候显示*/
    }
    
    /* 菜单样式 */
    .nav-menu {
      margin: 0;
      padding-left: 0;
      border: 1px solid #ccc;
      list-style: none;
      background-color: #000;
      color: #fff;
    }
    .nav-menu > li + li {
      border-top: 1px solid #ccc;
    }
    .nav-menu > li > a {
      display: block;
      padding: 0.8em 1em;
      color: #fff;
      font-weight: normal;
    }
    

    html添加事件

    <script type="text/javascript">
        (function() {
        var button = document.getElementById('toggle-menu');
        button.addEventListener('click', function(event) {
          event.preventDefault();
          var menu = document.getElementById('main-menu');
          menu.classList.toggle('is-open');
        });
      })();
    </script>
    

    注意:菜单项链接周围的内边距。因为是给移动设备设计,通常是触屏设备,所以关键的点击区域应该足够大,并很容易用一个手指点击

    现在效果如下:

    image.png

    示例-添加meta标签

    现在移动版设计已经完成,但是还差一个重要细节:视口的meta标签。

    这个HTML标签告诉移动设备,你已经特意将网页适配了小屏设备。如果不加这个标签,移动浏览器会假定网页不是响应式的,并且会尝试模拟桌面浏览器

    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    

    meta标签的content属性里包含三个选项:

    • 告诉浏览器当解析CSS时将设备的宽度作为假定宽度,而不是一个全屏的桌面浏览器的宽度
    • 当页面加载时,它使用initial-scale将缩放比设置为100%
    • 第三个选项user-scalable=no,阻止用户在移动设备上用两个手指缩放(不常用)

    对于第一个选项,可以明确设置width=320让浏览器假定视口宽度为320px,但是通常不建议这样,因为移动设备的尺寸范围很广。

    原则二 媒体查询

    引入

    媒体查询(mediaqueries)允许某些样式只在页面满足特定条件时才生效。这样就可以根据屏幕大小定制样式

    媒体查询使用@media规则选择满足特定条件的设备。一条简单的媒体查询如下代码所示。表示只有当设备的视口宽度大于等于560px的时候,才会给标题设置2.25rem的字号。如果视口宽度小于560px,那么里面的所有规则都会被忽略。

    @media(min-560px){
        .title>h1{
            font-size:2.25rem
        }
    }
    

    在媒体查询里更适合用em

    em是基于浏览器默认字号的(通常是16px)。下面将560px改成35em(560 / 16)。在这里,560px这个临界值被称为断点。

      @media(min-35em){
          .title>h1{
              font-size:2.25rem
          }
      }
    

    1.媒体查询方式

    • 用and关键字联合表示同时满足

      @media (min-20em)and(max-35em){...}
      
    • 用逗号分隔表示只需要满足多个条件之一

      @media (min-20em),(max-35em){...}
      

    2.媒体特征

    • min-width:匹配视口大于特定宽度的设备

    • max-width:匹配视口小于特定宽度的设备

    • min-height:匹配高度大于特定高度的视口

    • max-height:匹配高度小于特定高度的视口

    • orientation: landscape:匹配宽度大于高度的视口

    • orientation: portrait:匹配高度大于宽度的视口

    • min-resolution: 2dppx:匹配屏幕分辨率大于等于2dppx(dppx指每个CSS像素里包含的物理像素点数)的设备,比如视网膜屏幕

    • max-resolution: 2dppx:匹配屏幕分辨率小于等于2dppx的设备

      完整的媒体特征列表请访问MDN文档:@media

    3.媒体类型

    • @media screen:针对屏幕

    • @media print:可以控制打印时的网页布局,这样就能在打印时去掉背景图(节省墨水),隐藏不必要的导航栏。

      为了帮助用户打印网页,需要采取一些通用步骤。大多数情况下,需要将基础打印样式放在@media print {...}媒体查询内。使用display: none隐藏不重要的内容,比如导航菜单和页脚。当用户打印网页时,他们绝大多数情况下只关心网页的主体内容。还可以将整体的字体颜色设置成黑色,去掉文字后面的背景图片和背景色。大多数情况下,用通用选择器就能实现。下面的代码使用了!important,这样就不必担心被后面的代码覆盖

      @media print{
          *{
              color:black !importent;
              background:none !importent;
          }
      }
      

    给网页添加断点

    @media (min-35em){
      .title>h1{
        ...
      }
    }
    @media (min-50em){
      .title>h1{
        ...
      }
    }
    

    示例-中屏断点

    现在想在较大的屏幕中实现下面的布局:

    image.png

    @media (min-35em){
      .title>h1{
        font-size: 2.25rem;
      }
    }
    @media (min- 35em) {
      .page-header {
        padding: 1em; /*增加头部内边距*/
      }
    }
    @media (min- 35em) {
      .hero {
        padding: 5em 3em; /*增加主图的内边距和字号*/
        font-size: 1.2rem;
      }
    }
    @media (min- 35em) {
      main {
        padding: 2em 1em; /*增加主元素内边距*/
      }
    }
    

    接下来处理菜单样式。首先,要将下拉菜单的打开和关闭行为去掉;其次将菜单从垂直排列改为水平排列布局。

    /* 把菜单的切换按钮隐藏,让下拉菜单的内容显示 */
    @media (min- 35em) {
      .menu-toggle {
        display: none;
      }
      .menu-dropdown {
        display: block;
        /* 覆盖绝对定位 */
        position: static;
      }
    }
    
    /* 将菜单改为弹性容器,让菜单子元素扩展,填满屏幕宽度 */
    @media (min- 35em) {
      .nav-menu {
        display: flex;
        border: 0;
        padding: 0 1em;
      }
      .nav-menu > li {
        flex: 1;
      }
    
    
      .nav-menu > li + li {
        border: 0;
      }
      .nav-menu > li > a {
        padding: 0.3em;
        text-align: center;
      }
    }
    

    响应式的列

    @media (min- 35em) {
      .row {
        display: flex;  /*实现等宽列*/
        /* 使用负外边距将容器扩大,补偿列的外边距 */
        margin-left: -.75em;
        margin-right: -.75em;
       }
       .column {
         flex: 1; /*实现等宽列*/
         margin-right: 0.75em; /*添加列间距*/
         margin-left: 0.75em;
       }
     }
    

    现在效果如图:

    image.png

    原则三 流式布局

    引入

    流式布局,有时被称作液体布局(liquid layout),指的是使用的容器随视口宽度而变化。

    与固定布局相反。固定布局的列都是用px或者em单位定义。比如设定了800px宽的元素在小屏上如果超出视口范围,会出现水平滚动条,而流式容器会自动缩小以适应视口。

    在流式布局中,主页面容器通常不会有明确宽度,也不会给百分比宽度,但可能会设置左右内边距,或者设置左右外边距为auto,让其与视口边缘之间产生留白。

    在主容器中,任何列都用百分比来定义宽度。这样无论屏幕宽度是多少都能放得下主容器。用Flexbox布局也可以,设置弹性元素的flex-grow和flex-shrink(更重要),让元素能够始终填满屏幕。要习惯将容器宽度设置为百分比,而不是任何固定的值。

    网页默认就是响应式的。没添加CSS的时候,块级元素不会比视口宽,行内元素会折行,从而避免出现水平滚动条。加上CSS样式后,就需要你来维护网页的响应式特性了

    示例-大屏断点

    接下来要为下一个屏幕断点加上媒体查询,大视口下的网页布局最终效果如图:

    image.png

     /* 大屏断点 */
     @media (min- 50em) {
      .page-header {
        padding: 1em 4em;
      }
    }
    @media (min- 50em) {
      .hero {
        padding: 7em 6em;
      }
    }
    @media (min- 50em) {
      main {
        padding: 2em 4em;
      }
    }
    @media (min- 50em) {
      .nav-menu {
        padding: 0 4em;
      }
    }
    @media (min- 50em) {
      :root {
        font-size: 1.125em;
      }
    }
    

    处理表格

    html部分

    <table>
        <thead>
            <tr>
            <th>Country</th>
            <th>Region/Farm</th>
            <th>Tasting notes</th>
            <th>Price</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>Nicaragua</td>
                <td>Matagulpa</td>
                <td>Dark chocolate, almond</td>
                <td>$13.95</td>
            </tr>
            <tr>
                <td>Ethiopia</td>
                <td>Yirgacheffe</td>
                <td>Sweet tea, blueberry</td>
                <td>$15.95</td>
            </tr>
            <tr>
                <td>Ethiopia</td>
                <td>Nano Challa</td>
                <td>Tangerine, jasmine</td>
                <td>$14.95</td>
            </tr>
        </tbody>
    </table>
    

    如果表格的列太多,很容易超过屏幕宽度:

    image.png

    有一个办法是将表格强制显示为一个普通的块级元素:

    image.png

    这个布局由<table><tr><td>元素组成,现在对它们使用了display: block声明,覆盖了正常的table、table-row、table-cell的显示值。现在配合max-width媒体查询限制在小屏下才改变表格元素的显示:

    table {
      border-collapse: collapse;
    }
    th, td {
      border: 1px solid black;
      padding: 0.3em 0.5em;
    }
    table {
       100%;
    }
    @media (max- 30em) {
      table, thead, tbody, tr, th, td {
        display: block;
      }
      thead tr {
        position: absolute;
        top: -9999px;
        left: -9999px;
      }
      tr {
        margin-bottom: 1em;
      }
    }
    

    响应式图片

    在响应式设计中,图片需要特别关注。不仅要让图片适应屏幕,还要考虑移动端用户的带宽限制。

    • 保证图片充分压缩。在图片编辑器中选择“Save forWeb”选项能够极大地减小图片体积,或者用别的图片压缩工具压缩图片,比如tinypng网站

    • 避免不必要的高分辨率图片,而是否必要则取决于视口大小。也没有必要为小屏幕提供大图,因为大图最终会被缩小。

    不同视口大小使用不同的图片

    • 创建不同分辨率的副本

      .hero {
        padding: 2em 1em;
        text-align: center;
        background-image: url(coffee-beans-small.jpg);
        background-size: 100%;
        color: #fff;
        text-shadow: 0.1em 0.1em 0.3em #000;
      }
      
      @media (min- 35em) {
        .hero {
          padding: 5em 3em;
          font-size: 1.2rem;
          background-image: url(coffee-beans-medium.jpg);
        }
      }
      
      @media (min- 50em) {
        .hero {
          padding: 7em 6em;
          background-image: url(coffee-beans.jpg);
        }
      }
      
    • 使用srcset提供对应的图片

      这个属性是HTML的一个较新的特性。它可以为一个<img>标签指定不同的图片URL,并指定相应的分辨率。浏览器会根据自身需要决定加载哪一个图片

      <img alt="A white coffee mug on a bed of coffee beans"
             src="coffee-beans-small.jpg"
             srcset="coffee-beans-small.jpg 560w,
                     coffee-beans-medium.jpg 800w,
                     coffee-beans.jpg 1280w">
      

    有关响应式图片的更多内容,请访问jakearchibald网站上的文章The Anatomy of Responsive Images。

  • 相关阅读:
    Asp.NET 4.0 ajax实例DataView 模板编程1
    ASP.NET 4.0 Ajax 实例DataView模板编程 DEMO 下载
    部分东北话、北京话
    .NET 培训课程解析(一)
    ASP.NET 4.0 Ajax 实例DataView模板编程2
    ASP.NET Web Game 架构设计1服务器基本结构
    ASP.NET Web Game 构架设计2数据库设计
    TFS2008 基本安装
    Linux上Oracle 11g安装步骤图解
    plsql developer远程连接oracle数据库
  • 原文地址:https://www.cnblogs.com/sanhuamao/p/13681147.html
Copyright © 2011-2022 走看看