本篇文章主要探讨盒模型,以及内边距、边框、外边距的面试题与思考,也希望您能把您的思考和遇到的问题以评论的方式补充下,后期,我将会补充到文章中
可以说,页面就是由一个个盒模型堆砌起来的,每个HTML元素都可以叫做盒模型,盒模型由外而内包括:外边距(margin)、边框(border)、填充(亦称内边距)(padding)、内容(content)。它在页面中所占的实际宽度是margin + border + paddint + content 的宽度相加。
但是,盒模型有标准盒模型和IE的盒模型。
我们先来看两张图:
标准的(W3C)盒模型:

IE盒模型:

很简单,通过设置 box-sizing:content-box(W3C)/border-box(IE)就可以达到自由切换的效果。
dom.style.width/height
这种方法只能获取使用内联样式的元素的宽和高。
dom.currentStyle.width/height
这种方法获取的是浏览器渲染以后的元素的宽和高,无论是用何种方式引入的css样式都可以,但只有IE浏览器支持这种写法。
window.getComputedStyle(dom).width/height
这种方法获取的也是浏览器渲染以后的元素的宽和高,但这种写法兼容性更好一些。
dom.getBoundingClientRect().width/height
这种方法经常使用的场所是,计算一个元素的绝对位置(相对于视窗左上角),它能拿到元素的left、top、width、height 4个属性。
<html>
<style>
body{
background-color: gray;
}
div{
color: blue;
width: 100px;
background-color: pink;
border: 10px solid;
padding: 20px;
}
</style>
<body>
<div></div>
</body>
</html>
有一说一,当时被字节面试官问到这个问题,我是挺蒙蔽的,因为他这里不指考了一点,问题列一下:
答案:如图所示

这里需要注意:
<html>
<style>
body{
background-color: gray;
}
.big{
width: 400px;
height: 400px;
background-color: pink;
}
.small{
width: 100px;
height: 100px;
background-color: red;
border-radius: 50%;
overflow-wrap: break-word;
}
</style>
<body>
<div class="big">
<div class="small">
ddddddddddddddddddddddddddddddddddddddddddd
</div>
</div>
</body>
</html>
会超出圆形。原因如图所示,是因为border-radius只是改变视觉上的效果,实际上盒子占据的空间还是不变的。

这是网易有道的小姐姐面试官的问题,我承认我确实不知道这个问题!
真正意义上的inline-block水平呈现的元素间,换行显示或空格分隔的情况下会有间距,很简单的个例子:
我们使用CSS更改非inline-block水平元素为inline-block水平,也会有该问题:
.space a {
display: inline-block;
padding: .5em 1em;
background-color: #cad5eb;
}
<div class="space">
<a href="##">惆怅</a>
<a href="##">淡定</a>
<a href="##">热血</a>
</div>

去除inline-block元素间间距的N种方法
<div class="space">
<a href="##">
惆怅</a><a href="##">
淡定</a><a href="##">
热血</a>
</div>
或者是:
<div class="space">
<a href="##">惆怅</a
><a href="##">淡定</a
><a href="##">热血</a>
</div>
或者是借助HTML注释:
<div class="space">
<a href="##">惆怅</a><!--
--><a href="##">淡定</a><!--
--><a href="##">热血</a>
</div>
详细的可以看看这篇文章 去除inline-block元素间间距的N种方法
span {
width:200px;
}
没有变化
span{
height:200px;
}
没用变化
span{
padding:200px;
}
影响左右,不影响上下 ,span包裹的文字左右位置改变,上下位置不变,但背景色会覆盖上面元素的内容。 如图所示:
行内元素(inline-block)的padding左右有效 ,但是由于设置padding上下不占页面空间,无法显示效果,所以无效。
对于我们来说,我们经常写的简写是两个值或者一个值或者四个值,而三个值的,会比较少写,所以当时,我确实有点蒙了,因为我对于这个三个值各代表什么是死记硬背的!后来才发现,原来遵循一条非常简单的规则:
简单来说就是 这四个值,分别代表上、右、下、左。如果没有写下的话,那就下复制上的,同理左复制右的值。
因此, 你应该明白了
这么简单的规则,再也不会忘记了吧。
我们知道,padding可以这么设置
padding:100px
也可以
padding:20%
那当是百分比时是怎么计算的呢?
这不是很简单的问题吗?
就是根据父元素的宽度计算的
好家伙,我说怎么问那么简单的问题,原来是为了这个问题做铺垫
这个问题可以这么思考,如果不根据父元素,而是根据本身的宽度的话。那么当padding生效后,本身的宽度不就变大了吗?那么padding不是也要变大吗?这就陷入了死循环(哇塞!)。
或者要是本身没有宽度,那岂不是怎么设置padding都是无效的!!!
边距重叠:两个box如果都设置了边距,那么在垂直方向上,两个box的边距会发生重叠,以绝对值大的那个为最终结果显示在页面上。
边距重叠分为两种:
同级元素在垂直方向上外边距会出现重叠情况,最后外边距的大小取两者绝对值大的那个**
<section class="fat">
<style type="text/css">
.fat {
background-color: #ccc;
}
.fat .child-one {
width: 100px;
height: 100px;
margin-bottom: 30px;
background-color: #f00;
}
.fat .child-two {
width: 100px;
height: 100px;
margin-top: 10px;
background-color: #345890;
}
</style>
<div class="child-one"></div>
<div class="child-two"></div>
</section>
父子关系,如果子元素设置了外边距,在没有把父元素变成BFC的情况下,父元素也会产生外边距。
给父元素添加 overflow:hidden 这样父元素就变为 BFC,不会随子元素产生外边距,但是父元素的高会变化
<!--
。 -->
<section class="box" id="fat">
<style type="text/css">
#fat {
background-color: #f00;
overflow: hidden;
}
#fat .child {
margin-top: 10px;
height: 100px;
background-color: blue;
}
</style>
<article class="child"></article>
</section>
实际上,这也是第一种的变形。
header {
background: goldenrod;
}
h1 {
margin: 1em;
}
<header>
<h1>Welcome to ConHugeCo</h1>
</header>

可以看到其实是header的margin为0,然后h1的margin为1em,因此header和h1的margin发生了重叠,然后header的margin就取1em和0两个值中最大的值了,所以当然取1em啦。
(网上有说是因为margin的传递性,但我并不同意,因为我实践了一下,发现不管父盒子有没有margin-top,父盒子只会选择两者值中的最大值,跟传递性似乎没啥关系)
这个就是问设计了margin重叠的巧妙用处。
这个曾经有位面试官问过我,我不知道,我请教了他,他说,在flex布局前,要实justify-content: space-evenly的效果,利用浮动布局,然后给每个盒子设置margin-right,margin-left就可以实现了,这样就不用去单独地再去设置第一个盒子的margin-left和最后一个盒子的margin-right,那时候我信了。
后来越想越不对,不是说margin水平方向不会发生重叠问题吗????
但是根据面试官的思路来的话,在垂直方向似乎就讲的通了。
<html>
<style>
body{
background-color: gray;
}
ul{
width: 300px;
height: 170px;
background-color: blue;
border: 1px solid;
}
li{
margin-top: 20px;
margin-bottom: 20px;
width: 40px;
height: 30px;
background-color: orange;
}
</style>
<body>
<ul>
<li></li>
<li></li>
<li></li>
</ul>
</body>
</html>

或许你有更好的说法,欢迎下方留言评论补充!!!
那该怎么解决margin边距重叠的问题呢?
解决方法就是生成BFC
BFC的基本概念–BFC就是“块级格式化上下文”的意思,也有译作“块级格式化范围”。它是 W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。通俗的讲,就是一个特殊的块,内部有自己的布局方式,不受外边元素的影响。
总结:pdfo
<!-- BFC不与float重叠 -->
<section id="layout">
<style media="screen">
#layout{
background: red;
}
#layout .left{
float: left;
width: 100px;
height: 100px;
background: #664664;
}
#layout .right{
height: 110px;
background: #ccc;
overflow: auto;
}
</style>
<div class="left"></div>
<div class="right"></div>
<!-- 利用BFC的这一个原理就可以实现两栏布局,左边定宽,右边自适应。不会相互影响,哪怕高度不相等。 -->
</section>
<!-- BFC子元素即使是float也会参与计算 -->
<section id="float">
<style media="screen">
#float{
background: #434343;
overflow: auto;
}
#float .float{
float: left;
font-size: 30px;
}
</style>
<div class="float">我是浮动元素</div>
</section>
<section id="margin">
<style>
#margin{
background: pink;
overflow: hidden;
}
#margin>p{
margin: 5px auto 25px;
background: red;
}
#margin>div>p {
margin: 5px auto 20px;
background: red;
}
</style>
<p>1</p>
<div style="overflow:hidden">
<p>2</p>
</div>
<p>3</p>
<!-- 这样就会出现第一个p标签的margin-bottom不会和第二个p标签的margin-top重叠,这也是BFC元素的另一个原则,不会影响到外边的box,是一个独立的区域。 -->
</section>
这时候很多人会想到新建标签clear:both和float 方法,但是这两种方法并不推荐使用!
什么是clear:both
clear:both:本质就是闭合浮动, 就是让父盒子闭合出口和入口,不让子盒子出来
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
<style>
.fahter{
width: 400px;
border: 1px solid deeppink;
}
.big{
width: 200px;
height: 200px;
background: darkorange;
float: left;
}
.small{
width: 120px;
height: 120px;
background: darkmagenta;
float: left;
}
.footer{
width: 900px;
height: 100px;
background: darkslateblue;
}
.clear{
clear:both;
}
</style>
</head>
<body>
<div class="fahter">
<div class="big">big</div>
<div class="small">small</div>
<div class="clear">额外标签法</div>
</div>
<div class="footer"></div>
</body>
</html>

盒子最高的高度,然后与其同高。
优点:通俗易懂,方便
缺点:添加无意义标签,语义化差
不建议使用。
通过触发BFC方式,实现清除浮动
.fahter{
width: 400px;
border: 1px solid deeppink;
overflow: hidden;
}
优点:代码简洁
缺点:内容增多的时候容易造成不会自动换行导致内容被隐藏掉,无法显示要溢出的元素
不推荐使用
.clearfix:after{/*伪元素是行内元素 正常浏览器清除浮动方法*/
content: "";
display: block;
height: 0;
clear:both;
visibility: hidden;
}
.clearfix{
*zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/
}
<body>
<div class="fahter clearfix">
<div class="big">big</div>
<div class="small">small</div>
<!--<div class="clear">额外标签法</div>-->
</div>
<div class="footer"></div>
</body>
优点:符合闭合浮动思想,结构语义化正确
缺点:ie6-7不支持伪元素:after,使用zoom:1触发hasLayout.
推荐使用
.clearfix:after,.clearfix:before{
content: "";
display: table;
}
.clearfix:after{
clear: both;
}
.clearfix{
*zoom: 1;
}
<div class="fahter clearfix">
<div class="big">big</div>
<div class="small">small</div>
</div>
<div class="footer"></div>
优点:代码更简洁
缺点:用zoom:1触发hasLayout.
推荐使用
img{
width:50px;
border:1px solid #8e8e8e;
float:left;
}
<div style="float:left">
<img src="images/search.jpg"/>
<img src="images/tel.jpg"/>
<img src="images/weixin.png"/>
<img src="images/nav_left.jpg"/>
</div>
这种方式也不推荐,了解即可。
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我在MiniTest::Spec和Capybara中使用以下规范:find_field('Email').must_have_css('[autofocus]')检查名为“电子邮件”的字段是否具有autofocus属性。doc说如下:has_css?(path,options={})ChecksifagivenCSSselectorisonthepageorcurrentnode.据我了解,字段“Email”是一个节点,因此调用must_have_css绝对有效!我做错了什么? 最佳答案 通过JonasNicklas得到了答案:No
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/
我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:
对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs
我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案