CSS解析:定位和层叠上下文

许多开发人员对定位的理解很粗略,如果不完全了解定位,就很容易给自己挖坑。有时候可能会把错误的元素放在其他元素前面,要解决这个问题却没有那么简单。

一般的布局方法是用各种操作来控制文档流的行为。定位则不同:它将元素彻底从文档流中移走。它允许你将元素放在屏幕的任意位置。还可以将一个元素放在另一个元素的前面或后面,彼此重叠。

默认定位
<style>
div {
/* 初始值静态定位static,未被定位 */
postion:static;
}
</style>

使用静态定位,称之为未被定位
改成其他值后,说明元素被定位了。
定位的元素从文档流中移走了,意味着允许将元素放在屏幕任意位置,还可以放在另一个元素的前面或后面彼此重叠

一、固定定位

给一个元素设置position: fixed就能将元素放在视口的任意位置。这需要搭配四种属性一起使用:top、right、bottom和left。这些属性的值决定了固定定位的元素与浏览器视口边缘的距离。

比如,top: 3em表示元素的上边缘距离视口顶部3em。

<style>
div {// 可以将元素放在视口任意位置postion:fixed;//通过四个值控制元素与浏览器视口边缘的位置//同时四个值隐式制定元素的大小top:0;left:0;right:0;bottom:0;
}
</style>

(一)用固定定位创建模态框

我们要用这些属性创建一个如图所示的模态框。该模态框会在网页内容前弹出来,它会挡住网页内容,直到关闭该弹窗。
在这里插入图片描述

通常情况下,模态框用于要求用户阅读一些内容或者在下一步操作之前输入一些内容。比如,如图的模态框展示了一个表单,用户可以注册一个时事通讯。初始状态下用display:none隐藏弹窗,然后用JavaScript将display改成block以显示弹窗。

<body><header class="top-banner"><div class="top-banner-inner"><p>前往注册账号 <button id="open">注册</button></p></div></header><div id="modal" class="modal"><div class="modal-backdrop"></div><div class="modal-body"><button class="modal-close" id="close">close</button><h2>标题栏</h2><p>请注册电子邮件!</p><form><p><label for="email">email:</label><input type="text" name="email" /></p><p><button type="submit">提交</button></p></form></div></div>
</body>
<script type="text/javascript">var button = document.getElementById('open')var close = document.getElementById('close')var modal = document.getElementById('modal')button.addEventListener('click', function (e) {e.preventDefault()modal.style.display = 'block'})close.addEventListener('click', function (e) {e.preventDefault()modal.style.display = 'none'})
</script>

代码里的第一个元素是顶部条。它包含了触发模态框的按钮。第二个元素是模态框。它包括一个空的modal-backdrop,用来遮住页面剩余部分,将用户的注意力集中到弹窗的内容。弹窗内容在modal-body里。

body {font-family: Helvetica, Arial, sans-serif;/* 设置网页高度,让页面出现滚动条(只是为了演示) */min-height: 200vh;margin: 0;
}button {padding: 0.5em 0.7em;border: 1px solid #8d8d8d;background-color: white;font-size: lem;
}
.top-banner {padding: lem 0;background-color: #ffd698;
}.top-banner-inner {width: 80%;max-width: 1000px;margin: 0 auto;
}.modal {/*默认隐藏模态框。当要打开模态框的时候,JavaScript会设置display: block*/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;
}.modal-close {cursor: pointer;
}

在这段CSS里,我们使用了两次固定定位。第一次是modal-backdrop的蒙层,四个方向都设置为0。

这让蒙层填满整个视口。它还有一个背景色rgba(0, 0, 0, 0.5)。这个颜色符号指定了红、绿、蓝的值均为0,算出来是黑色。第四个值是“alpha”通道,它指定透明度:0是完全透明,1是完全不透明。0.5是半透明,因此该元素下面所有的网页内容就会变暗。

第二次固定定位了modal-body。它的四条边都在视口内:顶边和底边到视口对应的边缘为3em,左边和右边距离视口对应的边缘为20%。因为它的背景色为白色,所以模态框呈现为一个在屏幕居中的白色盒子。

虽然可以随意滚动网页,但是背景和模态框主体都不会动。打开页面,我们看到屏幕上方有一个带按钮的淡黄色顶部条。点击按钮打开定位的模态框。

因为是固定定位,所以即使滚动页面,模态框的位置也不会变(为了演示,我们特地将body上的min-height值设得很大,撑出了滚动条)​。点击模态框顶部的Close按钮,关闭弹窗。这个按钮现在的位置不太对,我们稍后会调整它的位置。

(二)控制定位元素的大小

定位一个元素时,不要求指定四个方向的值,可以只指定需要的方向值,然后用width和/或height来决定它的大小,也可以让元素本身来决定大小。请看如下声明。

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

这段代码会将元素放在距离视口顶部和右边1em的位置,宽度为视口宽度的20%。它省略bottom和height属性,元素的高度由自身的内容决定。

例如,这可以用于将一个导航菜单固定到屏幕上。即使用户滚动网页内容,该元素的位置也不会改变。因为固定元素从文档流中移除了,所以它不再影响页面其他元素的位置。

别的元素会跟随正常文档流,就像固定元素不存在一样。也就是说它们通常会在固定元素下面排列,视觉上被遮挡。这对于模态框来说没问题,因为我们希望模态框出现在最前面的中间位置,直到用户关闭它。

而对于其他固定元素,比如侧边导航栏,就需要注意不要让其他内容出现在它下面。通常给其他内容加一个外边距就能解决该问题。比如,将所有内容放在容器里,容器设置right-margin:20%。外边距会流到固定元素下面,内容就不会跟导航栏重叠。

二、绝对定位

固定定位让元素相对视口定位,此时视口被称作元素的包含块(containing block)​。

绝对定位的行为也是如此,只是它的包含块不一样。绝对定位不是相对视口,而是相对最近的祖先定位元素。

跟固定元素一样,属性top、right、bottom和left决定了元素的边缘在包含块里的位置。

<style>
div {// 可以将元素放在祖先定位元素的任意位置postion:absolute;//同样,通过四个值控制元素与浏览器视口边缘的位置top:0;left:0;right:0;bottom:0;
}

(一)让Close按钮绝对定位

为了演示绝对定位,我们重新设置Close按钮的位置,将其放在模态框的右上角,如图所示。
在这里插入图片描述

我们需要将Close按钮设置为绝对定位。因为它的父元素modal-body是固定定位的,所以会成为Close按钮的包含块。

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

这段代码将按钮放在距离modal-body顶部0.3em、右侧0.3em的位置。通常情况下,就像本例一样,包含块是元素的父元素。如果父元素未被定位,那么浏览器会沿着DOM树往上找它的祖父、曾祖父,直到找到一个定位元素,用它作为包含块。

如果祖先元素都没有定位,那么绝对定位的元素会基于初始包含块(initialcontaining block)来定位。初始包含块跟视口一样大,固定在网页的顶部。

(二)定位伪元素

Close按钮已经定位好了,只是过于简陋。对于这种Close按钮,用户通常期望看到一个类似于x的图形化显示,如图所示。
在这里插入图片描述

你可能首先想到将按钮里的文字close换成x,但是这会导致可访问性的问题:辅助的屏幕阅读器会读按钮里的文字。因此要给这个按钮一些有意义的提示。在使用CSS之前,HTML本身必须有意义。

相反,你可以用CSS隐藏close,并显示x。总共需要两步。首先将按钮的文字挤到外面,并隐藏溢出内容。然后将按钮的::after伪元素的content属性设置为x,并让伪元素绝对定位到按钮中间。

.modal-close {position: absolute;top: 0.3em;right: 0.3em;padding: 0.3em;cursor: pointer;font-size: 2em;/*让按钮变成方形*/height: 1em;width: 1em;/*让元素里的文字溢出并隐藏*/text-indent: 10em;overflow: hidden;border: 0;
}
.modal-close::after {position: absolute;line-height: 0.5;top: 0.2em;left: 0.1em;text-indent: 0;/*    添加 Unicode 字符 U+00D7(乘法符号)*/content: '\00D7';
}

以上代码清单明确指定按钮为1em大小的方形。text-indent属性将文字推到右边,溢出元素它的确切值不重要,只要大于按钮宽度即可。

由于text-indent是继承属性,需要在伪类元素选择器上设为0,因此x便不会缩进。伪类元素现在是绝对定位。因为它表现得像按钮的子元素一样,所以定位的按钮就成为其伪元素的包含块。设置一个较小的line-height让伪元素不要太高,用top和left属性让它在按钮中间定位。

绝对定位是定位类型里的重量级选手。它经常跟JavaScript配合,用于弹出菜单、工具提示以及消息盒子。我们将用绝对定位来构建一个下拉菜单,但在此之前,我们需要先看看它的搭档:相对定位。

三、相对定位

相对定位可能是最不被理解的定位类型。当第一次给元素加上position: relative的时候,你通常看不到页面上有任何视觉改变。相对定位的元素以及它周围的所有元素,都还保持着原来的位置。

如果加上top、right、bottom和left属性,元素就会从原来的位置移走,但是不会改变它周围任何元素的位置

<style>
div {postion:relative;top:1em;left:2em;
}

如图所示,四个inline-block元素,给第三个元素加上三个额外的属性:position: relative、top: 1em、left: 2em,将其从初始位置移走,但是其他元素没有受到影响。它们还是围绕着被移走元素的初始位置,跟随着正常的文档流。
在这里插入图片描述
设置top: 1em将元素从原来的顶部边缘向下移动了1em;设置left: 2em将元素从它来的左侧边缘向右移动了2em。这可能导致元素跟它下面或者旁边的元素重叠。在定位中,也可以使用负值,比如bottom: -1em也可以像top: 1em那样将元素向下移动1em。

跟固定或者绝对定位不一样,不能用top、right、bottom和left改变相对定位元素的大小。这些值只能让元素在上、下、左、右方向移动。可以用top或者bottom,但它们不能一起用(bottom会被忽略)​。同理,可以用left或right,但它们也不能一起用(right会被忽略)​。

有时可以用这些属性调整相对元素的位置,把它挤到某个位置,但这只是相对定位的一个冷门用法。更常见的用法是使用position: relative给它里面的绝对定位元素创建一个包含块。

实际应用:
由于绝对定位的最近父元素必须是定位元素,所以将父元素设置为相对定位。既不影响父元素,又可以实现绝对定位。

(一)创建一个下拉菜单

接下来我们用相对和绝对定位创建一个下拉菜单。它的初始状态是一个简单的矩形,当用户鼠标悬停到上面时,会弹出一个链接列表。
在这里插入图片描述

 <div class="container"><naV><div class="dropdown"><div class="dropdown-label">下拉菜单</div><div class="dropdown-menu"><ul class="submenu"><li>首页</li><li>新闻中心</li><li>服务支持</li><li>关于我们</li></ul></div></div></nav><h1>这是一个h1标题</h1></div>

将它添加到HTML中,放在<div class="modal">的结束标签后面。这段代码包含了一个容器元素,之后我们会将它的内容居中,并让它跟顶部条的内容对齐。我还在弹出列表下面放了一个<h1>标签,以展示弹出列表如何出现在其他网页内容前面。

下拉菜单容器包含两个子元素:一个始终显示的灰色矩形标签以及一个下拉菜单。下拉菜单用显示和隐藏表示菜单展开和收起。因为它会是绝对定位的,所以当下拉菜单显示时不会改变网页的布局,这意味着它显示时会出现在其他内容前面。

.container {width: 80%;max-width: 1000px;margin: 1em auto;
}.dropdown {display: inline-block;position: relative;
}.dropdown-label {padding: .5em 1.5em;border: 1px solid #ccc;background-color: #eee;
}.dropdown-menu {display: none;position: absolute;left: 0;top: 2.1em;min-width: 100%;background-color: #eee;
}.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: .5em 1.5em;background-color: #eee;color: #369;text-decoration: none;
}.submenu > li > a:hover {background-color: #fff;
}

当移动鼠标指针到主菜单标签时,下拉菜单就会从下面弹出。请注意,这里是在整个容器上设置:hover状态来打开菜单。也就是说只要鼠标停在它的任何内容上,无论是dropdown-label还是dropdown-menu,菜单都会保持打开状态。

绝对定位的dropdown-menu设置了left: 0,让其左边和整个容器的左侧对齐。然后它使用top: 2.1em将其顶部边缘放在标签下面(算上内边距和边框,标签高2.1em)​。

min-width为100%,保证它至少等于容器的宽度(容器宽度由dropdown-label决定)​。之后用submenu类给下来菜单内的菜单加上样式。​

(二)创建CSS三角形

下拉菜单距离完美还差一步。现在它已能正常工作,但用户无法一眼察觉到主菜单标签下面还有更多内容。我们来给标签加上一个小的向下箭头,告诉用户还有更多内容。

我们可以用边框画一个三角形当作向下箭头。这里用标签的::after伪元素来画三角形,然后使用绝对定位将它放到标签的右边。大多数情况下,我们会给一个元素加上较细的边框,通常1px或者2px就够了,但如果把边框变得像图那样粗呢?图中给每条边都加了独特的颜色,用来标出每条边的起始位置。

在这里插入图片描述
注意观察角上两条边的边缘接触的地方:它们形成了一个对角边。再观察一下将元素的宽和高缩小到0时会发生什么​。所有的边都汇聚到一起最后在中间连接起来了。
在这里插入图片描述

元素四周的边都变成了三角形。顶部的边箭头指向下边,右边的边指向左边,以此类推。基于这个现象,可以用一条边作为三角形,然后将剩下的边设置为透明。元素的左右边都透明,而顶部边可见,就会如图所示,形成一个简单的三角形。
在这里插入图片描述

我们给dropdown-label::after伪元素加上样式,做一个三角形,并让它绝对定位。

  .dropdown-label {/*增加右侧内边距给箭头留位置*/padding: .5em 2em .5em 1.5em;border: 1px solid #ccc;background-color: #eee;}.dropdown-label::after {content: "";position: absolute;right: 1em;/*在标签的右边定位元素*/top: 1em;border: 0.3em solid;border-color: black transparent transparent;}.dropdown:hover .dropdown-label::after {top: 0.7em;border-color: transparent transparent black;}

伪元素因为没有内容,所以没有宽或高。然后用border-color简写属性设置上边框为黑色,左右和下面的边框为透明,构造一个向下的箭头。dropdown-label右边用内边距留出了空间,用来放三角形。最后的效果如图所示。

在这里插入图片描述
打开菜单,箭头方向反转,朝向上面,表示菜单可以被关闭。微调top值(从1em到0.7em)​,让向上的箭头看起来跟向下的箭头处于相同的位置。

另外你也可以用一个图片或者背景图来实现箭头,但是用短短几行CSS代码就可以为用户免去不必要的网络请求。加上这个小小的箭头,能给网站或应用程序增色不少。

这项技术还可以用来构建其他复杂形状,比如梯形、六边形和星形。查看用CSS构建的各种形状,可以访问css-tricks网站上的文章The Shapes of CSS。

四、层叠上下文

定位非常有用,但也需要弄清楚它会带来什么后果。当把一个元素从文档流中移除时,我们就需要管理之前由文档流处理的所有事情了。

首先要确保元素不会不小心跑到浏览器视口之外,导致用户会看不到元素。

其次要保证元素不会不小心挡住重要内容。

最后还有层叠的问题。在同一页面定位多个元素时,可能会遇到两个不同定位的元素重叠的现象。有时我们会发现“错误”的元素出现在其他元素之前。

(一)层叠顺序

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

顺序很重要,因为如果元素刚好重叠,后绘制的元素就会出现在先绘制的元素前面。通常情况下(使用定位之前)​,元素在HTML里出现的顺序决定了绘制的顺序。考虑以下代码里的三个元素:

<div>one</div>
<div>two</div>
<div>three</div>

它们的层叠行为如图所示。这里使用了负的外边距让元素重叠,但并未使用任何定位。后出现在标记里的元素会绘制在先出现的元素前面。
在这里插入图片描述
定位元素时,这种行为会改变。浏览器会先绘制所有非定位的元素,然后绘制定位元素。默认情况下,所有的定位元素会出现在非定位元素前面。如图所示,给前两个元素加了position: relative,它们就绘制到了前面,覆盖了静态定位的第三个元素,尽管元素在HTML里的顺序并未改变。
在这里插入图片描述
注意,在定位元素里,第二个定位元素还是出现在第一个定位元素前面。定位元素会被放到前面,但是基于源码的层叠关系并没有改变。

在这里插入图片描述
也就是说在上述网页里,模态框和下拉菜单都会出现在静态内容之前(符合预期)​,但是源码里后出现的元素会绘制在先出现的元素之前。

解决这个问题的一个办法是在源码里将<div class="modal">及其内容移到下拉菜单后面。通常情况下,模态框要放在网页内容的最后,</body>关闭标签之前。大多数构建模态框的JavaScript库会自动这样做。因为模态框使用固定定位,所以不必关心它的标记出现在哪里,它会一直定位到屏幕中间。

改变固定定位元素的标记位置不会产生不好的影响,但是对相对定位或绝对定位的元素来说,通常无法用改变标记位置的方法解决层叠问题。相对定位依赖于文档流,绝对定位元素依赖于它的定位祖先节点。这时候需要用z-index属性来控制它们的层叠行为。

(二)使用Z-INDEX控制层叠顺序

z-index属性的值可以是任意整数(正负都行)​。z表示的是笛卡儿x-y-z坐标系里的深度方向。拥有较高z-index的元素出现在拥有较低z-index的元素前面。拥有负数z-index的元素出现在静态元素后面。

使用z-index是解决网页层叠问题的第二个方法。该方法不要求修改HTML的结构。将modal-backdrop的z-index设置为1,将modal-body的z-index设置为2(确保模态框的主体在蒙层前面)​。

 .modal-backdrop {/*当打开模态框时,用半透明的蒙层遮挡网页剩余内容*/position: fixed;top: 0;right: 0;bottom: 0;left: 0;background-color: rgba(0, 0, 0, 0.5);z-index: 1;}.modal-body {/*给模态框的主体定位*/position: fixed;top: 3em;bottom: 3em;right: 20%;left: 20%;padding: 2em 3em;background-color: white;/*允许模态框主体在需要时滚动*/overflow: auto;z-index: 2;}

z-index的行为很好理解,但是使用它时要注意两个小陷阱。

第一,z-index只在定位元素上生效,不能用它控制静态元素。

第二,给一个定位元素加上z-index可以创建层叠上下文。

(三)层叠上下文

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

实际上将层叠上下文里的所有元素一起绘制会造成严重的后果:层叠上下文之外的元素无法叠放在层叠上下文内的两个元素之间。

换句话说,如果一个元素叠放在一个层叠上下文前面,那么层叠上下文里没有元素可以被拉到该元素前面。同理,如果一个元素被放在层叠上下文后面,层叠上下文里没有元素能出现在该元素后面。

<div class="box one positioned">one<div class="absolute">nested</div>
</div>
<div class="box two positioned">two</div>
<div class="box three">three</div>

这段代码包含了三个盒子,其中两个被定位,并且z-index为1,第一个盒子里面有一个绝对定位的元素,它的z-index为100。

body {margin: 40px;
}
.box {display: inline-block;width: 200px;line-height: 200px;text-align: center;border: 2px solid black;background-color: #ea5;margin-left: -60px;vertical-align: top;
}
.one {margin-left: 0;
}
.two {margin-top: 30px;
}
.three {margin-top: 60px;
}
.positioned {position: relative;background-color: #5ae;z-index: 1;
}
.absolute {position: absolute;top: 1em;right: 1em;height: 2em;background-color: #fff;border: 2px dashed #888;z-index: 100;line-height: initial;padding: 1em;
}

虽然第一个盒子里绝对定位的子元素nested的z-index很高,但还是出现在第二个盒子后面,因为它的父元素,即第一个盒子形成的层叠上下文在第二个盒子后面
在这里插入图片描述
叠放在第二个盒子后面的第一个盒子是一个层叠上下文的根。因此,虽然nested所在div的z-index值很高,但是它内部的绝对定位元素不会跑到第二个盒子前面。在浏览器开发者工具里试验一下,感受这种关系,改变每个元素的z-index看看会发生什么。

给一个定位元素加上z-index是创建层叠上下文最主要的方式,但还有别的属性也能创建,比如小于1的opacity属性,还有transform、filter属性。由于这些属性主要会影响元素及其子元素渲染的方式,因此一起绘制父子元素。文档根节点(<html>)也会给整个页面创建一个顶级的层叠上下文。

所有层叠上下文内的元素会按照以下顺序,从后到前叠放:
❑ 层叠上下文的根
❑ z-index为负的定位元素(及其子元素)
❑ 非定位元素
❑ z-index为auto的定位元素(及其子元素)
❑ z-index为正的定位元素(及其子元素)

如果不根据组件的优先级定义清晰的层叠顺序,那么一个样式表很容易演变成一场z-index大战。如果没有清晰的说明,开发人员在给一个模态框之类的元素添加样式时,为了不被其他元素遮挡,就会设置一个高得离谱的z-index,比如999999。

这样的事情重复几次后,大家就只能凭感觉给一个新的组件设置z-index。如果你使用预处理器,比如LESS或SASS​,或者你支持的所有浏览器都支持自定义属性​,就能很方便地处理这个问题。将所有的z-index都定义为变量放到同一个地方,如下代码片段所示。这样就能清晰地看到哪些元素在前哪些元素在后。

--z-loading-indicator:100;
--2-nav-menu:200;
--z-dropdown-menu:400;
--z-modal-backdrop:300;
--z-modal-body:410;

将增量设为10或者100,这样就能在需要的时候往中间插入新值。

如果发现z-index没有按照预期表现,就在DOM树里往上找到元素的祖先节点,直到发现层叠上下文的根。然后给它设置z-idnex,将整个层叠上下文向前或者向后放。还要注意多个层叠上下文嵌套的情况。

网页很复杂时,很难判断是哪个层叠上下文导致的问题。因此,在创建层叠上下文的时候就一定要多加小心,没有特殊理由的话不要随意创建,尤其是当一个元素包含了网页很大一部分内容的时候。

尽可能将独立的定位元素(比如模态框)放到DOM的顶层,结束标签</body>之前,这样就没有外部的层叠上下文能束缚它们了。
有些开发人员会忍不住给页面的大量元素使用定位。一定要克制这种冲动。定位用得越多,网页就越复杂,也就越难调试。如果你定位了大量元素,就回头评估一下现在的情况,尤其是当你发现很难调试出自己想要的布局时,一定要反思。

如果可以用别的方法实现某个布局,应该优先用那些方法。如果能够依靠文档流,而不是靠明确指定定位的方式实现布局,那么浏览器会帮我们处理好很多边缘情况。记住,定位会将元素拉出文档流。

一般来说,只有在需要将元素叠放到别的元素之前时,才应该用定位。

五、粘性定位

人们已经用四种主要的定位类型(静态、固定、绝对以及相对)很长时间了,不过现在浏览器还提供了一种新的定位类型:粘性定位(sticky positioning)​。

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

网页刚加载的时候,侧边栏的位置一切正常。网页滚动,它也跟着滚动直到滚到快要离开视口的时候,它会锁定在那个位置。当网页的剩余部分继续滚动时,它却好像固定定位的元素一样停留在屏幕上。
在这里插入图片描述
接下来修改网页结构,定义两栏。在HTML里将容器改成如代码所示的代码。把之前的内容(下拉菜单和网页标题)放在左边栏,再添加一个右边栏放“affix”菜单。

<div class="container"><main class="col-main"><nav><div class="dropdown"><div class="dropdown-label">下拉菜单</div><div class="dropdown-menu"><ul class="submenu"><li>首页</li><li>新闻中心</li><li>服务支持</li><li>关于我们</li></ul></div></div></nav><h1>这是一个h1标题</h1></main><aside class="col-sidebar"><div class="affix"><ul class="submenu"><li>首页</li><li>新闻中心</li><li>服务支持</li><li>关于我们</li></ul></div></aside>
</div>

接下来更新CSS,将容器设为弹性容器,设置两栏的宽度。本例复用了下拉菜单的子菜单的样式,当然你也可以给侧边栏添加其他的元素和样式。

.container {display: flex;width: 80%;max-width: 1000px;margin: lem auto;min-height: 100vh;
}
.col-main {flex: 1 80%;
}
.col-sidebar {flex: 20%;
}
.affix {position: sticky;top: 1em;
}

以上代码主要用来设置两栏布局。最后只用了两句声明来给affix元素定位。

top值设置了元素最终固定的位置:距离视口的顶部1em。因为粘性元素永远不会超出父元素的范围,所以本例中affix不会超出col-sidebar的范围。

当滚动页面的时候,col-sidebar会一直正常滚动,但是affix会在滚动到特定位置时停下来。如果继续滚动得足够远,粘性元素还会恢复滚动。这种情况只在父元素的底边到达粘性元素的底边时发生。注意,只有当父元素的高度大于粘性元素时才会让粘性元素固定,因此这里特意给弹性容器加上min-height,以便让父元素足够高。

.sticky {//粘性定位元素的表现与其父元素有关。position: sticky;//必须指定 top、right、bottom、left 四个阈值的其中之一,粘性定位才会生效top: 10px;
}

使用粘性定位时要注意浏览器的兼容性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/52198.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚幻地形高度图生成及测试

虚幻地形高度图生成及测试 虚幻引擎地形系统将高度数据存储在高度图中&#xff0c;这是一个灰阶图像&#xff0c;使用黑白色值来存储地貌高程。在高度图中&#xff0c;纯黑色值表示最低点&#xff0c;纯白色值表示最高点。支持16位灰阶PNG、8位灰阶r8及16位灰阶r16格式。 本文…

硬刚苹果还得是华为

文&#xff5c;琥珀食酒社 作者 | 璇子 牛皮啊 华为发三折叠不意外 意外的是 这各种翻转简直颠覆想象 市面上没见过这么能“翻转”的&#xff1f; 要不怎么说硬刚苹果 还得看华为 就跟你同天怎么了&#xff1f; 拼创新、拼技术、拼热度 你就说哪比你差吧&#xff1f…

基于VUE的校园二手物品交易管理系统的设计与实现 (含源码+sql+视频导入教程)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于VUE的校园二手物品交易管理系统8拥有两种角色 管理员&#xff1a;闲置物品管理、订单管理、用户管理 用户&#xff1a;登录注册、购物车、发布闲置物品、评论、发货、收货地址管理等…

电力设计院10大排行榜!这个大院屠榜!

今天晚上阅读了中国电力规划设计协会《2022年度电力勘测设计行业统计分析报告》&#xff0c;这本报告是依据协会会员企业统计报表数据进行编制分析的。报告共收集了167家勘测设计企业上报的数据信息&#xff0c;统计的企业数量较2021 年166家企业增加1 家。 按业务板块划分为&…

element ui form 表单出现英文提示的解决方案

场景再现&#xff1a; 在使用 form 表单的时候&#xff0c;一般都需要对表单元素进行验证&#xff0c;错误就出现在了这里&#xff0c;除了配置的错误信息&#xff0c;还会出现一个 英文校验提示&#xff0c;如下图&#xff1a; 解决方案 出现的原因是在el-form-item中使用…

Tensorflow2 如何扩展现有数据集(缩放、随机旋转、水平翻转、平移等),从而提高模型的准确率 -- Tensorflow自学笔记14

实际生活中的数据集&#xff0c;往往不是标准的数据&#xff0c;而是有倾斜角度、有旋转、有偏移的数据&#xff0c;为了提高数据集的真实性&#xff0c;提高模型预测的准确率&#xff0c;可以用ImageDataGenerator函数来扩展数据集 import tensorflow as tffrom tensorflow.k…

(二)ASP.NET Core WebAPI项目的启动地址设置

上一篇介绍了ASP.NET Core WebAPI项目创建&#xff0c;可参考&#xff1a; 1.webAPI的访问地址 1) 启动时&#xff0c;选择CoreWebAPI(项目名称)运行项目 可以看到打开浏览器后的地址是&#xff1a;applicationUrl"\"launchUrl 2) 启动时&#xff0c;选择IIS Expre…

Ansys Zemax | 在OpticStudio中仿真单模光纤耦合

附件下载 联系工作人员获取附件 准确分析耦合效率在光纤耦合系统的设计中至关重要。本文演示了如何在OpticStudio中使用多种光纤耦合效率分析。 概要 OpticStudio序列模式可以很好地模拟单模光纤耦合效率。本文演示了如何设置耦合系统&#xff0c;并研究了序列模式下可用于…

redis分布式锁和lua脚本

业务场景&#xff1a;多个线程对共同资源的访问&#xff1a;库存超卖/用户重复下单的原因 解决方法一&#xff1a;利用jvm内置锁&#xff0c;将非原子性操作变成原子性操作 Synchronized锁的是对象&#xff0c;对象必须是单例的。锁的是this,代表当前所在的类&#xff0c;这个…

RabbitMQ 基础架构流程 数据隔离 创建用户

介绍 publisher&#xff1a;消息发送者-exchange&#xff1a;交换机&#xff0c;复制路由的消息-queue&#xff1a;队列&#xff0c;存储消息consumer&#xff1a;消息的消费者 工作流程 publisher消息发送者 -> exchange 交换机 -> queue 队列 -> consumer 消息的消…

流动会场:以声学专利为核心的完美移动场地—轻空间

流动会场作为一种全新的活动场所选择&#xff0c;凭借其便捷的移动性与先进的声学设计&#xff0c;正逐渐成为各类演出、会议和文化活动的热门场地。其独特之处不仅在于搭建速度快、灵活性高&#xff0c;还在于其核心技术——声学专利的强大支持。 专利声学设计&#xff0c;打造…

【LeetCode】06.Z字形变换

题目要求 解题思路 首先映入我们脑海的就是暴力。这一方法可行&#xff0c;但是时间复杂度空间复杂度很高&#xff0c;因此我们使用找规律的方法。这样的话我们可以模拟插入下标&#xff0c;这样的话很容易发现首行和末行插入的位置刚好是d2*n-2&#xff0c;而中间行的两个位置…

windows下安装elasticSearch和kibana

下载es 下载地址官网 下载后是个压缩包(elasticsearch-8.15.0-windows-x86_64)&#xff0c;解压即可 启动 配置 改一下 /conf/jvm.options文件&#xff0c;最后加一行编码配置&#xff0c;这个是为了启动后防止控制台乱码 -Dfile.encodingGBK启动es 依赖jdk8环境&#xf…

【SQL笔试题】SN_1 连续登陆系列问题

简介 连续登陆天数场景描述是对一个特定情境或活动连续发生的天数进行详细的阐述。这种描述通常用于展示某个事件或活动的持续时间&#xff0c;以及它对参与者或环境产生的影响。 常见的应用场景&#xff1a; 用户留存分析&#xff1a;通过跟踪用户的连续登录天数&#xff0…

C语言中static与extern关键字的深入解析

在C语言编程中&#xff0c;static和extern是两个非常重要的关键字&#xff0c;它们各自有着独特的用途。本文将深入探讨这两个关键字的工作原理、底层实现机制以及在实际开发中的应用。 static关键字 1. 原理与作用 static关键字用于声明变量或函数具有特定的作用域和生命周…

【自考zt】【数据结构】【22.04】

一、单选 二、填空 三、解答 四、算法阅读 五、算法设计

Tensorflow常见激活函数 -- Tensorflow自学笔记10

激活函数 激活函数是用来加入非线性因素的&#xff0c;因为线性模型的表达能力不够。引入非线性激活函数&#xff0c;可使深层神经网络的表达能力更加强大。 一. 什么是优秀的激活函数&#xff1f; 优秀的激活函数应满足: 1. 非线性: 激活函数非线性时&#xff0c;多层神经网…

第四届摩纳哥智能化可持续发展码头交流会

第四届摩纳哥智能化可持续发展码头交流会 摩纳哥游艇码头顾问公司&#xff08;M3&#xff09;认为游艇行业的绿色转型需要做到从游艇本身到游艇码头的360度全方位可持续化发展&#xff0c;因此&#xff0c;继今年3月的摩纳哥智能游艇交流会后&#xff0c;他们将于2024年9月22日…

<数据集>二维码识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;1601张 标注数量(xml文件个数)&#xff1a;1601 标注数量(txt文件个数)&#xff1a;1601 标注类别数&#xff1a;1 标注类别名称&#xff1a;[QR] 序号类别名称图片数框数1QR16016286 使用标注工具&#xff1a;l…

swagger简单使用学习

注意 一下基于spring-boot 3.0.2版本&#xff0c;该版本不支持springfox-swagger2 2.9.2会报错&#xff0c;无法访问swagger 安装 在pomx文件中添加对应的依赖 <!-- swagger --><dependency><groupId>org.springdoc</groupId><artifactId>spr…