likes
comments
collection
share

深入解析CSS-盒模型

作者站长头像
站长
· 阅读数 13

GitHub:github.com/ForeverYoun…

深入解析CSS系列:

案例一:实现如下布局

深入解析CSS-盒模型

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Home</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <style>
      body {
        background-color: #eee;
      }
      header {
        color: #fff;
        background-color: #0072b0;
        border-radius: 0.5em;
      }
      main {
        display: block//避免ie将main渲染成行内元素;
      }
      .main {
        background-color: #fff;
        border-radius: 0.5em;
        float: left;
        width: 70%;
      }
      .sidebar {
        padding: 1.5em;
        background-color: #fff;
        border-radius: 0.5em;
        float: left;
        width: 30%;
      }
    </style>
  </head>
  <body>
    <header>
      <h1>Franklin Running club</h1>
    </header>
    <div class="container">
      <main class="main">
        <h2>Come join us!</h2>
        <p>
          The Franklin Running club meets at 6:00pm every Thursdayat the town
          square. Runs are three to five miles, at yourown pace .
        </p>
      </main>
      <aside class="sidebar">
        <div class="widget"></div>
        <div class="widget"></div>
      </aside>
    </div>
  </body>
</html>

mainsidebar共同占有宽度为:30%+70%+2*1.5em > 100%

可以使用 calc设置sidebar区域的宽度为calc(30% - 3em)

除此之外,更好的办法是调整盒模型:(但是全局调整盒模型可能会影响一些第三方组件的样式,需要将第三方组件恢复为content-box)

*,
::before,
::after {
  box-sizing: border-box;
}

接下来为mainsidebar设置间距。也有两种方案。

方案一是将sidebarmargin-left设置为1%,将其宽度改为29%,但是百分比是相对于父元素的完整宽度的,这会导致随着父元素宽度不同,间距大小不同。

方案二是使用em结合calc

      .sidebar {
        padding: 1.5em;
        background-color: #fff;
        border-radius: 0.5em;
        float: left;
		
        margin-left: 1.5em;
        width: calc(30% - 1.5em);
      }

接下来处理高度---实现等高列。

通常最好避免给元素指定明确的高度。普通文档流是为限定的宽度和无限的高度设计的。内容会填满视口的宽度,然后在必要的时候折行。因此,容器的高度由内容天然地决定,而不是容器自己决定。

实现等高列,也有两种方案:CSS表格和Flexbox

方案一:CSS表格

      .main {
        background-color: #fff;
        border-radius: 0.5em;
        /* float: left;  */
        width: 70%;
		
        display: table-cell; 
      }
      .sidebar {
        padding: 1.5em;
        background-color: #fff;
        border-radius: 0.5em;
        /* float: left; */
        /* margin-left: 1.5em; */
        width: 30%;

        display: table-cell;
      }

      .container {
        display: table;
        border-spacing: 1.5em 0;
        width: 100%;
      }
      .wrapper {
        margin: 0 -1.5em;
      }

总结:

  1. 表格布局替代浮动布局:给容器设置display:table,给每一列设置display:table-cell
  2. 由于table元素宽度不会自动扩展为100%,所以要手动设置。
  3. 外边距不会作用于table-cell元素,需要在容器上设置border-spacing
  4. 负的外边距抵消border-spacing对表格外边缘的副作用。

方案二:Flexbox

	  .container {
        display: flex;
      }

给容器设置display: flex,它就变成了一个弹性容器,子元素默认等高。


接下来填充侧边栏的内容:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Home</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <style>
      *,
      ::before,
      ::after {
        box-sizing: border-box;
      }
      body {
        background-color: #eee;
      }
      header {
        color: #fff;
        background-color: #0072b0;
        border-radius: 0.5em;
        padding: 1em 1.5em;
      }
      main {
        display: block//避免ie将main渲染成行内元素;
      }
      .main {
        background-color: #fff;
        border-radius: 0.5em;
        /* float: left;  */
        width: 70%;
      }
      .sidebar {
        padding: 1.5em;
        background-color: #fff;
        border-radius: 0.5em;
        /* float: left; */
        margin-left: 1.5em;
        width: 30%;
      }

      .container {
        display: flex;
      }

      .button-link {
        display: block;
        padding: 0.5em;
        color: #fff;
        background: #0090c9;
        text-align: center;
        text-transform: uppercase;
        text-decoration: none;
      }
    </style>
  </head>
  <body>
    <header>
      <h1>Franklin Running club</h1>
    </header>
    <div class="container">
      <main class="main">
        <h2>Come join us!</h2>
        <p>
          The Franklin Running club meets at 6:00pm every Thursdayat the town
          square. Runs are three to five miles, at yourown pace .
        </p>
      </main>
      <aside class="sidebar">
        <a class="button-link">follow us on teitter</a>
        <a class="button-link">like us on facebook</a>
      </aside>
    </div>
  </body>
</html>

侧边栏两个按钮因为没有外边距会紧挨到一起,如果加上margin-top: 1.5em,第一个按钮的顶部外边距加上容器顶部的内边距产生的空间大于其余三个方向的留白,显得很不匀称。

可以使用相邻兄弟组合器给按钮之间加上一个外边距:选中同一个父元素下紧跟在其他button-link后面的button-link元素。

      .button-link + .button-link {
        margin-top: 1.5em;
      }

除了上述方法还有一个通用的解决方案:猫头鹰选择器

      body * + * {
        margin-top: 1.5em;
      }

该选择器开头是一个通用选择器(*),它可以选中所有元素,后面是一个相邻兄弟组合器(+),最后是另一个通用选择器。它因形似一只眼神空洞的猫头鹰而得名。猫头鹰选择器功能接近此前介绍的选择器:.social-button + .social-button,但是它不会选中直接跟在其他按钮后面的按钮,而是会选中直接跟在其他元素后面的任何元素。也就是说,它会选中页面上有着相同父级的非第一个子元素


最终代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Home</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <style>
      *,
      ::before,
      ::after {
        box-sizing: border-box;
      }
      body * + * {
        margin-top: 1.5em;
      }

      body {
        background-color: #eee;
      }
      header {
        color: #fff;
        background-color: #0072b0;
        border-radius: 0.5em;
        padding: 1em 1.5em;
      }
      main {
        display: block//避免ie将main渲染成行内元素;
      }
      .main {
        background-color: #fff;
        border-radius: 0.5em;
        width: 70%;
        padding: 1em 1.5em;
      }
      .sidebar {
        padding: 1.5em;
        background-color: #fff;
        border-radius: 0.5em;
        margin-left: 1.5em;
        width: 30%;
        /* 消除猫头鹰选择器带来的副作用 */
        margin-top: 0;
      }

      .container {
        display: flex;
      }

      .button-link {
        display: block;
        padding: 0.5em;
        color: #fff;
        background: #0090c9;
        text-align: center;
        text-transform: uppercase;
        text-decoration: none;
      }
      .sponsor-link {
        display: block;
      }
    </style>
  </head>
  <body>
    <header>
      <h1>Franklin Running club</h1>
    </header>
    <div class="container">
      <main class="main">
        <h2>Come join us!</h2>
        <p>
          The Franklin Running club meets at 6:00pm every Thursdayat the town
          square. Runs are three to five miles, at yourown pace .
        </p>
      </main>
      <aside class="sidebar">
        <a class="button-link">follow us on teitter</a>
        <a class="button-link">like us on facebook</a>
        <a class="sponsor-link">become a sponsor</a>
      </aside>
    </div>
  </body>
</html>

案例一知识点总结:

  1. 关于盒模型:box-sizing默认值为content-box,表示所设置的宽高为content区域的宽高,不包含padding,border,;设置为border-box后,所设置的宽高为content,padding,border的总和。常用border-box
  2. 关于元素溢出:overflow最好使用auto而不是scroll,因为auto只有在元素溢出的时候才出现滚动条。
  3. 关于子元素的百分比高度:百分比参考的是元素容器块的大小,但是容器的高度通常是由子元素的高度决定的。这样会造成死循环,浏览器处理不了,因此它会忽略这个声明。要想让百分比高度生效,必须给父元素明确定义一个高度。
  4. 关于表格布局:border-spacing属性来定义单元格的间距。该属性接受两个长度值:水平间距和垂直间距。该属性会作用于表格的外边缘。
  5. 相邻兄弟选择器(+):当第二个元素紧跟在第一个元素之后,并且两个元素都是属于同一个父 element 的子元素,则第二个元素将被选中。
  6. 猫头鹰选择器:通常只在有并列元素,或者有多列布局时这样使用

min-heightmax-height

min-height定义元素最少应该具备的高度。正常情况下元素的高度由自身决定,如果设置了min-height,当元素高度不足min-height时,高度为min-height,元素内容超过min-height时,容器自然地扩展高度,以容纳内容。

同理,max-height允许元素自然地增高到一个特定界限。如果到达这个界限,元素就不再增高,内容会溢出。还有类似的属性是min-widthmax-width,用于限制元素的宽度。

垂直居中内容

  1. 可以用一个自然高度的容器吗?给容器加上相等的上下内边距让内容居中。
  2. 容器需要指定高度或者避免使用内边距吗?对容器使用display: table-cellvertical-align: middle
  3. 可以用Flexbox吗? 如果不需要支持IE9,可以用Flexbox居中内容。
  4. 容器里面的内容只有一行文字吗?设置一个大的行高,让它等于理想的容器高度。这样会让容器高度扩展到能够容纳行高。如果内容不是行内元素,可以设置为inline-block
  5. 容器和内容的高度都知道吗?将内容绝对定位。(只有当前面提到的方法都无效时才推荐这种方式。)
  6. 不知道内部元素的高度?用绝对定位结合变形(transform)。(还是只有当前面提到的方法都无效时才推荐该方法。)

负外边距

负外边距的具体行为取决于设置在元素的哪边。如果设置左边或顶部的负外边距,元素就会相应地向左或向上移动,导致元素与它前面的元素重叠,如果设置右边或者底部的负外边距,并不会移动元素,而是将它后面的元素拉过来。给元素底部加上负外边距并不等同于给它下面的元素顶部加上负外边距(即使效果是一样的)。

如果不给一个块级元素指定宽度,它会自然地填充容器的宽度。但如果在右边加上负外边距,则会把它拉出容器。如果在左边再加上相等的负外边距,元素的两边都会扩展到容器外面。

外边距折叠

只有上下外边距会产生折叠,左右外边距不会折叠。

文字折叠

段落(<p>)默认有1em的上外边距和1em的下外边距。这是用户代理的样式表添加的,但当前后叠放两个段落时,它们的外边距不会相加产生一个2em的间距,而会折叠,只产生1em的间隔。

<h2>标题的外边距为0.83em

折叠外边距的大小等于相邻外边距中的最大值。

多个外边距重叠

即使将段落放在多个div中嵌套,渲染结果都一样:所有的外边距都会折叠到一起。若嵌套的div没有设置外边距,将作为0进行计算。

容器外部折叠

容器外部折叠指的是比如:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Home</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <style>
      *,
      ::before,
      ::after {
        box-sizing: border-box;
      }

      header {
        color: #fff;
        background-color: #0072b0;
        border-radius: 0.5em;
      }
    </style>
  </head>
  <body>
    <header>
      <h1>Franklin Running club</h1>
    </header>
    <main>外边距容器外部折叠使间距发生在header和main元素之间</main>
  </body>
</html>

网页标题是<h1>,用户代理样式表给它底部设置的外边距为0.67em(21.44px)。它的父元素是<header>,没有设置任何外边距。因为它们的底部外边距相邻,所以会折叠,导致<header>下方出现了21.44px的外边距。这两个元素顶部的外边距也发生了折叠。

某种情况下,我们希望<h1>的外边距留在<header>中,但是外边距不一定在理想的地方折叠。

实现上述需求有两种方法:第一就是手动给header元素添加内边距,第二是利用“弹性子元素的外边距不会折叠”这一特性。

如下方法可以防止外边距折叠:

  1. 对容器使用overflow: auto(或者非visible的值),防止内部元素的外边距跟容器外部的外边距折叠。这种方式副作用最小。
  2. 在两个外边距之间加上边框或者内边距,防止它们折叠。
  3. 如果容器为浮动元素、内联块、绝对定位或固定定位时,外边距不会在它外面折叠。
  4. 当使用Flexbox布局时,弹性布局内的元素之间不会发生外边距折叠。网格布局同理。
  5. 当元素显示为table-cell时不具备外边距属性,因此它们不会折叠。此外还有table-row和大部分其他表格显示类型,但不包括table、table-inline、table-caption
转载自:https://juejin.cn/post/7270861556031356928
评论
请登录