专栏首页PHP 开发前台开发从头说起:理解css盒模型

前台开发从头说起:理解css盒模型

在掌握了丰富而强大的css选择符之后,就具备了将css样式根据需要应用到网页中任何元素的能力。能够应用规则了,接下来就需要熟练掌握规则的制定方法——什么样的属性组合能够实现什么样的效果。一般的颜色、字体、字号、行高等的设置比较容易掌握,而初学者在应用css的时候,主要头疼的还是如何用css实现复杂的网页布局,从两栏布局、三栏布局,到表单设计等。在布局的时候,实际上主要是借助元素的宽、高、定位、浮动、边距、边框、间距、背景颜色、背景图片的组合来实现的。而所有这些,都要基于对css盒模型的理解。网上对盒模型的论述很多(推荐阅读《彻底理解css盒子模式》),我这里想从实用的角度来谈谈。

网上有两张著名的图片,分别以2D和3D的形式描述css盒模型:

通过这两张图,一般来说对于margin、border、background-color、background-image、padding以及width和height有较直观的了解了。

更为重要的是要了解以下几点:

  1. 对于所有以“块(block)”方式呈现的元素都具备这个模型的特性,而不只是div;
  2. margin是以所指定元素的父级元素(常称为“容器”)为基准的;
  3. 一个元素(通常为块元素)在页面中所占的位置尺寸为:宽度= width + padding-left + padding-right + border-left-width + border-right-width + margin-left + margin-right;高度 = height + padding-top + padding-bottom + border-top-width + border-bottom-width + margin-top + margin-bottom;(部分浏览器有差异,以后再具体讨论);
  4. background-color将填满border内部的全部范围;background-image默认以图片左上角对齐border内部左上角点,然后完整显示整个图片(超出部分不予显示),如果图片尺寸不足铺满整个范围,图片默认重复自己直至铺满或超出范围;
  5. background-image将叠加到background-color之上;通过指定图片的对齐方式,可以改变background-image的位置;

通过以上这些规则的组合,就能在有限的元素组合下,实现各种修饰性效果。一个简单的例子如下:

将一个15像素高,颜色为#c00的纯色图片

放入一个高度为30像素,背景色为#f00的块元素,设定图片在Y轴方向不平铺,在x轴方向平铺。结果得到一个类似下图的效果:

这是简单的由背景色与背景图组合实现的效果。根据这样的原理,当我们的文档结构有两层时,例如:<a href=”#"><span>文字</span></a>,我们可以通过由a元素的背景颜色图片和span元素的背景颜色图片组合,从而得到较为复杂的效果,例如:

这个按钮效果,用纯图片很容易实现,但是用图片实现就会面临一个问题:不通用。如果要通用,应该把文字和背景图片分离开来,同时,由于文字有多有少,因此按钮的宽度要是可变的,但是按钮并不是从左到右完全一致的背景,于是不能使用一张图片进行横向平铺,按照以前的做法,可能会使用一个一行三列的表格,第一个单元格放入左侧的图片,中间的单元格放文字和平铺的背景,右边的单元格放右侧的图片。这种思维传递到了“div+css”布局思维模式下,于是就出现了这样的结构:

<div class=”button”><div class=”left”></div><div class=”center”></div><div class=”right”></div>

这个结构的出现,就是为了实现自适应宽度的按钮,今天依然存在。实际上,使用上面的a+span的基本结构,就能实现这个效果。将中间平铺部分和左侧或右侧的边缘图片组合在一起,重复部分做得宽一些,作为a的背景图片,把另一侧的图片作为span的背景图片覆盖到a的背景图片上。组合起来看上去就成为一个整体。代码如下:

效果如下:

a {display:block;width:200px;height:36px;background:url(button.gif) no-repeat right bottom;}
a span {display:block;line-height:36px;background:url(button.gif) no-repeat left top;color:#fff;text-decoration:none;text-align:center;}

用到的背景图片如下:

这个例子很简单,但是需要对“背景组合”有足够的理解,能够想到应用。而要想到如此应用,首先是对于盒模型中的“background”足够的理解。否则,就只会想到三个div(或者其它元素组合方式),但是由于左右两个结构完全一样,为了区分它们,只好使用class或者id来标记。这就是我在上一篇中所提到的不必要的class和id。

除了利用display:block让行内元素改变为块元素从而使用盒模型特征外,在浮动的时候,也经常会用到盒模型的一些特征。再举个例子:

使用浮动布局的时候,并列呈现的浮动元素中的第一个如果设置与浮动方向相同的margin,则IE 6下会出现margin加倍的bug(这就是著名的IE6浮动边距加倍bug)。为了解决这个问题,很多人喜欢给一组浮动元素的第一个加上class=”first”,从而可以对这个元素单独应用样式。或者对这一组浮动元素加上display:inline的属性以解决这个bug。

上述两种方式都是没有使用hack选择符或者类似“_margin”这样的非标准属性的很好的hack方式。但是,如果不是非用margin不可,只要使用padding来代替margin,就能解决这个问题。或者采用与浮动方向相反的margin也可以。不需要任何额外的hack。这也是在充分理解盒模型的基础上,由于对这个bug的了解,从而在实现样式的时候直接避开,而不是出现了之后再用额外手段去hack。

对盒模型的理解,除了margin、border、padding、width、height五大属性以及两种背景的应用之外,还要了解父级元素与子元素之间的关系。比如父元素没有设置尺寸,而对子元素设置margin-top属性,在某些浏览器下,本来是想针对父元素的边缘设置margin,结果margin被设置到了父元素之外,造成父元素与外部元素的margin。这种情况,将子元素的margin改成父元素的padding,也可以在不改变表现的情况下实现相同的效果。

要想通过对盒模型特征的充分应用来减少css中的hack使用,或者以更简洁的代码实现更复杂的效果,需要对盒模型不断地尝试和总结。这是《css权威指南》之类的经典巨著也没法教给你的。

只有越理解盒模型,才能越好地利用浮动和定位来实现复杂、精确的布局。关于浮动的问题,下一次我们再一起来了解一下。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • webkit中BFC元素临近浮动元素时的边距bug

    一直以来我们都很熟悉IE的“浮动边距加倍”的bug,并且绝大多数重构人员都已经很擅长在需要浮动时就直接绕过他。其实以webkit为核心的浏览器,包括但不限于Sa...

    小李刀刀
  • 写在 Laravel 5.5 发布之前

    Laravel 5.5 将于 2017年7月发布,这将是继 Laravel 5.1 之后的下一个长期支持版本,相比之前发布的几个“中间版本”而言,意义重大。目前...

    小李刀刀
  • Laravel 5.0 发布, 海量新特性!!

    译注: 期待 Laravel 5.0 已经很久很久了, 之前跳票说要到今年一月份发布. 从一月份就一直在刷新官网和博客, 始终没有更新的消息, 前几天终于看到官...

    小李刀刀
  • 用php来查询graphql

    类似于SQL,GraphQL也是一种ql(query language)。不过是用于API查询,可以更加直观的取到所需要查询的数据。普通的RESTful API...

    yumusb
  • C++反汇编第一讲,认识构造函数,析构函数,以及成员函数

              C++反汇编第一讲,认识构造函数,析构函数,以及成员函数 以前说过在C系列下的汇编,怎么认识函数.那么现在是C++了,隐含有构造和析构函数 ...

    IBinary
  • 《五》Swoole 多协议 多端口 的应用

    Swoole 支持了2种类型的自定义网络通信协议 :EOF结束符协议、固定包头+包体协议。

    新亮
  • 《二》Swoole Task 的应用

    Swoole 的实现方式是 worker 进程处理数据请求,分配给 task 进程执行。

    新亮
  • php中文语义分析实现方法示例

    最近公司有个需求要做文章关键词提取,发现有个波森语义分析,还不错,把其http接口封装了一下, 发布到packagist上了。

    砸漏
  • 本地iptables转发脚本

    明哥的运维笔记
  • TCP协议浅析TCP概述TCP可靠数据传输TCP流量控制TCP连接管理

    上图我们进行一个分析,以便搞清楚tcp序列号和ack的应用 首先,hostA作为发送方给B发送数据,随机选择一个序列号seq = 42,也就是这段segmen...

    desperate633

扫码关注云+社区

领取腾讯云代金券