从三栏自适应宽度布局到css布局的讨论,自适应

缘起

人家都说康奈尔笔记法,很好用呢,能抵抗遗忘曲线,让你的笔记事半功倍,有兴趣的同学自行百度哈。

网上有很多现成的模板,下载下来之后吧,看着好像在上面写英文可能更方便一点,行距很小,而且还有网址在上面,心里不是很乐意的说呢。后来想着自己在word或者excel里面做一个模板出来,后来愣是不会把一个表格的一行设置成占总表格的70%,最终放弃,后来想起来,css里面是可以用cm做单位的呀,为什么不自己写一个呢,只用div就可以了呀

垂直居中作为一个常见布局形式,或多或少的会给不熟悉页面布局的人带来困扰,这里参考Steven Bradley总结的六种布局方法,带给大家一些新的思考。这里介绍的方法都是常规的CSS方法,可以垂直居中行内元素以及块级元素,实际上CSS3的flex布局方法可以完美解决类似垂直居中,水平居中,分散对齐等常见的布局形式,具体可以参看阮一峰老师的这篇文章Flex 布局教程。

从三栏自适应宽度布局到css布局的讨论,自适应css

      如何实现一个三栏自适应布局,左右各100px,中间随着浏览器宽度自适应?

      第一个想到的是使用table布局,设置table的宽度为100%,三个td,第1个和第3个固定宽度为100px,那么中间那个就会自适应了,下面是一个实时的demo:

left  middle  right 

      但是table布局是不推荐的,table布局是css流行之前使用的布局,有很多缺点:当table加载完之前,整个table的都是空白的,table将数据和排版参和在一起,使得页面混乱,并且table布局修改排版十分麻烦和困难。

      如果不用table布局,那么第二个想到的办法是采用float,让左边的div float left,右边的div float right,如下边所示:

Action 1 先让左右两个div浮动

float left  float right 

      中间还有一个div,如果将中间的div排在第二:

<div style="float:left;">left</div>
<div>middle</div>
<div style="float:right;">right</div>

     那么效果是这样的:

Action 2 右边的div浮动到了第二行

left  middle  right 

      因为div默认的display为block,如果不设置width的话,块级元素会尽可能多地占用水平空间。如果设置了width: 200px,效果是这样的:

Action 3 右边的div仍然浮动到了第二行

float left  middle  right 

      第三个div仍然会换行,因为float right会排到当前行尽可能右边的位置,即它的容器盒的边缘或者挨着的上一个float的元素,如果当前行没有空间的话,会不断地往下移,直到有足够的空间。由于middle是一个块盒,即使设置了width,当前行的空间也会被占用,所以right只能到下一行才有空间。

      同时注意到middle虽然设置了200px,但是看起来和left一样是100px宽了。这是因为float了的元素虽然在正常的文档流之内,但是只是让相邻(非float)的元素的内容围绕着它排列,它仍然占据相邻元素的background和border空间。如果给middle添加一个白色的border,那么看起来是这样的:

Action 4 浮动的元素占据了文档流相应元素的背景和边缘空间

float left  middle  right 

       明显看到,float left的元素占据了middle的background和border的空间,同时middle的内容围绕着left排列。理解这点很重要。

       假设middle里面有个p标签,而p标签的内容比较长,那么围绕的效果是这样的:

Action 5 浮动的环绕效果

float left  middle 

环绕的元素一旦超出float元素高度之后,会以正常的宽度显示

float right 

      正如上面的注释一样,在float元素的那一行,相邻的元素的内容的宽度将会缩短,以适应float元素占去的宽度,而一旦超过float元素的区域,相邻元素的内容显示宽度就会正常。

      由于默认的div会占一行,所以不能将middle放在第二个div,得放到第三个div。把第二个div和第三个div换一下顺序:

<div style="float:left;">left</div>
<div style="float:right;">right</div>
<div>middle</div>

      先让float right的div渲染,再渲染middle的div。因为渲染left之后,left的那一行仍然有空间,这是由于float left之后,只会占据当前行的background和border,而当前行还有很大的空间,于是第二步渲染right时就和left同一行了,效果:

Action 6 先渲染左右两个div,再渲染中间的div

left  right  middle 

       如果不设置middle的width,那么middle将围绕着left和right环绕,和left一样,right也会占用middle的空间。

Action 7 中间的div围绕着左右的div环绕

left  right  ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ middle围绕着left和right环绕,同时left和right占据着middle的空间 ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~

       为了让middle和left/right中间有一个margin值,设置下middle的左右margin各为110px,这样就和左右和中间就各有10px的间距:

Action 8 设置中间div的margin值为100px 10px

left  right  middle 设置margin: 0 110px;

       这种办法的优点是实现简单,支持性好。

       这种自适应宽度的原理是利用了float的围绕特性,占据自然文档流的background/border位置。这个围绕特性不仅会影响当前行的内容,还会影响下一行的内容,如下说明:

<p>第一段内容,略<img src="" style="float:left;"></img></p>
<p>第二段内容,略</p>

Action 8 float元素占据了下一行的空间

第一段落围绕着图片排列图片的float属性也影响了第二段落,也就是说float会占据自然文本流相应位置元素的背景和边框,即使和float的元素不在同一行

 

       网上还有一种margin负值法。margin负值法的步骤是:第一步让中间的middle占100%的宽度,而middle的内容设置左右margin各为100px,这样就实现了middle居中自适应宽度的效果:

<div style="width:100%;">
      <div style="margin: 0 100px;">middle</div>
</div>

middle

       接下来让left的margin-left值为-100%,由于这个比例是相对于浏览器窗口大小的,所以要是left和middle是在同一行的话,left就可以跑到middle的最左边。但是因为middle的容器盒是一个普通的div,会占据一整行,left就会排到下一行,这个时候设置margin-left为一个负数时就跑出屏幕了。所以让middle float一下,left就会排到第一行最左边,同时middle覆盖在上面:

<div style="width:100%; float:left;">
      <div style="margin: 0 100px;">middle</div>
</div>
<div style="margin-left: 0">left</div>

middle left

      从上面可以看到:这样实现,导致left的内容被挤出目标区域,因为正如上面所说,middle占据了left的背景空间,上面的情况是把它占满了,left内容只能overflow了。所以这样实现是有问题的,得让left也向左float一下,这样left就紧挨在middle后面了,由于middle占了100%的宽度,所以再让left向左边margin了-100%后,left就刚好在最左边了。

<div style="width:100%; float:left;">
      <div style="margin: 0 100px;">middle</div>
</div>
<div style="float: left; margin-left: -100%;">left</div>

middle left

       注意这里,虽然left float之后看起来也是被排到下一行了,但和默认的div独占一行是不一样的。float之后的left仍然和middle是同一行的,因为空间不足的时候,float只是把当前行盒的空间撑大,就和一个div块盒里面有很多个display为inline-block的行内级盒是同样的道理。例如:

<style>
     button{ width: 150px; }
</style>
<div style="width: 300px;">
    <button>按钮1</button> 
    <button>按钮2</button> 
    <button style="margin-left: -200px;">按钮3</button>
</div>

     按钮3设置了一个很大的margin-left的负值后并不是跑到屏幕外了,而是在和其它两个按钮同一行的位置,显示如下:

按钮1 按钮2 按钮3

     注意,设置了float的元素并不是把display改成了 inline-block,大部份display的css计算值都变成了block,同时对原本是display: flex的没有改变:

指定值 计算值
inline block
inline-block block
inline-table table
table-row block
table-row-group block
table-column block
table-column-group block
table-cell block
table-caption block
table-header-group block
table-footer-group block
flex flex, but float has no effect on such elements
inline-flex inline-flex, but float has no effect on such elements
other unchanged

来自MDN

     由上表可看出,一个span设置了float: left/right之后,就不需要再设置成display: block/inline-block了,直接设置宽高即可。

     回归正题,left的div设置了margin-left: -100%之后就跑到左边去了,而right也是同样道理,将right的margin-left相应地设置为-100px,就跑到最右边去了:

<div style="width:100%; float:left;">
      <div style="margin: 0 100px;">middle</div>
</div>
<div style="margin-left: -100%;">left</div>
<div style="margin-right: -100px;">right</div>

Action 9 margin负值法

middle left right

 

      下面讨论第三种方法,使用display: table-cell

      由于table的展示拥有自适应的特点,因此把需要自适应宽度的middle的display属性设置为table-cell。

<div style="float:left;">left</div>
<div style="float:right;">right</div>
<div style="display:table-cell;">middle</div>

      效果如下:

left right middle

      发现table-cell的宽度是根据内容自适应的,这里是要根据浏览器窗口自适应,因此给middle添加一个很大的width就可以了,例如width:2000px:

Action 10 让中间的div使用table-cell自适应宽度 left right middle

      由于ie6/7不支持display: table-cell,所以如果要支持ie6/7的话,就得用display: inline-block,ie6/7的inline-block和标准不一样,它是用来触发hasLayout特性,使元素拥有布局属性。作用在行内元素,可以使得宽高等设置生效,如果作用在块元素,仅是触发布局特性,还要再设置成inline才是行内块元素,如果不设置inline效果就跟table-cell很像。不一样的地方是:设置了width:2000px,导致太长会换行,因此得用ie6/7的hack,设置*width: auto重新改会width值就可以了:

<style>
    .middle{
         display: table-cell;
         *display: inline-block; /* _和*开头的只有ie6/7会识别 */
         width: 2000px;
         *width: auto;
    }
</style>
<div style="float:left;">left</div>
<div style="float:right;">right</div>
<div class="middle">middle</div>

      但是笔者认为:为了互联网的美好,不要再兼容ie6/7了,甚至ie8。

 

      接下来,继续第四种方法,使用flex布局,十分简单:只需要将容器设置为display: flex,然后再设置middle的flex-grow为1即可:

<section style="display:flex;"></section>
<div>left</div>   <!--宽度为100,省略-->
<div style="flex-grow: 1;">middle</div>
<div>right</div>

Action 11 使用flex-grow自适应宽度

left middle flex-grow: 1 right

      flex-grow: 1的作用是把middle的宽度置为flex容器的剩余宽度,就达到了自适应的目的。flex的使用不作全面介绍,详情可查看CSS-Tricks: A Complete Guide to Flexbox

      但是flex布局ie的支持性较差,具体查看caniuse.

 

      最后再分析另外一个自适应的例子,某个元素的宽度要根据其它元素的宽度自适应。如下图所示,排名的位数变化可能会很大,导致最右边的文字要自适应:

        根据上面的一番分析,这个例子就不难实现了,如下面的分析,p标签里的文字宽度就能自适应了:

<div style="width:320px;"> <span style="width:14px;float:left;">排名</span> <span style="font-size:40px;float:left;">89</span>
<img style="width:44px;height:44px;float:left;" src="..."></img> <p>你的好友会编程的银猪在土壕榜中排名89</p> </div>

      实际效果:

排名 1 你的好友会编程的银猪在土壕榜中排名1

排名 6783 你的好友会编程的银猪在土壕榜中排名6783

 

 

       使用float是最简单的,还可以尝试使用flex布局,主要用到flex-shrink属性,flex-shrink的作用是定义收缩比例,容器内的子元素的宽度和若超出容器的宽度时,将按比例收缩子元素的宽度,使得宽度和等于容器的宽度。如下所示,将前面三个span/img的flex-shrink设置为0,而p的flex-shrink设置为1,这样子使得溢出的宽度都在p标签减去,就能够达到p标签宽度自适应的效果。

   <style>
        span,img{ flex-shrink: 0; }
        p{ flex-shrink: 1; }
   </style> 
   <div style="display:flex;width:320px;">                               
        排名
        89        
        <img style="width:44px;height:44px;" src="..."></img>
        <p>你的好友会编程的银猪在土壕榜中排名89</p>
    </div>

      实时效果:

排名 89 你的好友会编程的银猪在土壕榜中排名89 排名 1890 你的好友会编程的银猪在土壕榜中排名1890

 

 

       上文综合分析了最原始的table布局,然后就是float布局、table-cell、margin负值法、以及flex布局来实现自适应宽度的实现和原理,重点讨论了float的一些特性。如果上面的分析有错误,还望指正。

 

参考:

  1. CSS Float Theory: Things You Should Know

  2. CSS Tricks: All About Floats

  3. CSS-Tricks: display

  4. Understanding Floats

  5. 视觉格式化模型

 

如何实现一个三栏自适应布局,左右各100px,中间随着浏览器宽度自适应? 第一个想到的...

实现

  1. 先把一个div设置成A4纸的大小,宽21cm,高29.7cm

        <div id="abody">
        </div>
    

    #abody { width: 21cm; height: 29.7cm; margin: 0 auto; overflow: hidden; padding: 1.5cm 1.2cm 1.2cm 2.5cm;}
    
  2. 给A4纸这么大的div里面加两个浮动的div,一个往左,占用29%的空间,一个往右,占用68%的空间

    <div id="main" class="main le">
            <div class="aline">提示</div>
            <div class="aline"></div>
    </div>
    <div id="sider" class="main ri">
            <div class="aline">笔记</div>
            <div class="aline"></div>
    
    </div>
    <div id="footer" class="footer">
    
            <div class="aline doubleline">概要</div>
            <div class="aline"></div>
    </div>
    

    用css的border分开两栏图片 1

    .main {height: 75%; overflow: hidden;}
    
        .le { width: 28.99999%; border-right: double 3px #666; float: left; }
        .ri { width: 69.99999%; float: right; }
    
  3. 往大框里面写一行一行的横线,用一个div 的aline类实现,html见上面

    这里如果你的编辑器支持emmet的话,写一个div.aline*42,就会有42行相同的div出现了。然后用css的border属性画出一条条的线出来。

    .aline { height: 0.9cm; border-bottom: 1px; border-bottom-style: dashed; border-bottom-color: #999; 
                margin-right: 8px; color: #eee; line-height: 0.9cm;}
    
  4. 再在左右两个大框的后面放一个div,清除浮动,放概要部分。

    <div id="main" class="main le">
            <div class="aline">提示</div>
            <div class="aline"></div>
    </div>
    <div id="sider" class="main ri">
            <div class="aline">笔记</div>
            <div class="aline"></div>
    
    </div>
    <div id="footer" class="footer">
    
            <div class="aline doubleline">概要</div>
            <div class="aline"></div>
    </div>
    

    ,里面的首行,用实线分出来5R笔记的下部分结构来

    .footer {clear: both; overflow: hidden;}
    .doubleline { border-top: double 3px #666;}
    
  5. 就这样,很简单的哈

    再见2017,你好,2018。
    想拿着直接打印着用的话,在这里

正文

通过CSS实现水平居中相当简单。当被居中的元素是内联元素(行内元素)时,我们可以使用text-align:center在父元素中水平居中。当元素是一个块级元素时,我们给定它的宽度,然后把它的左边距和右边距设置成auto,也可以实现水平居中。

考虑到text-align:center可以水平居中,为了垂直居中大部分人首先想到的应该是vertical-align属性。看起来很符合逻辑,如果你熟悉表格布局,你很有可能使用过valign属性,这样也会让你相信vertical-align应该也是这样。

然而valign只对表格单元有效,vertical-align也是类似的,它即对表格单元有效,又对一些内联元素有效。

vertical-align值的意义和其父级内联元素有关。

  • 在一行文本内,其值是相对于行高的。
  • 在一个表格单元内,其值是相对于表格高度算法,通常是指一行的高度。

很遗憾vertical-align对块级元素不起作用,像一个div里面的段落。我们大多数可以想出来,这并不是所有的解决方案。

尽管我们有其他方法居中块级元素,我们仍然可以在恰当的时候使用vertical-align。选择那个方法主要依赖于你想居中在何种容器元素中。

关于vertical-align更多介绍,可以看看鑫大神的文章,点这里

1.line-height方法

这种方法适用于垂直居中单行文本的情况。我们要做的只是给包含文本的元素设置一个行高(line-height),只要保证行高大于文本的字体大小就可以了。

通常情况下,文本的上下会有相同的间距,文本刚好垂直居中。

大部分方法都建议把元素的height和元素的line-height设置成一样的值。我认为设置height是没有必要的,但是如果仅仅设置line-height不起作用,设置height可能就是解决办法(这样看来,最好height,line-height都设置,并且值保持一致)。

html

<div id="parent">
    <div id="child"> Text here </div>
<div>

css

#child{
    line-height: 200px;
}

上面的代码可以运行在任意的浏览器中,但是它只对单行文本有效,如果文本换行你必须使用另外的方法。200px是随意设置的,你可以设置成任意大于字体大小的值。

本文由糖果派对电玩城发布于独家专题,转载请注明出处:从三栏自适应宽度布局到css布局的讨论,自适应

您可能还会对下面的文章感兴趣: