前言
更新日志有一个非常独特的地方就是他的日志列表是以一种特殊的节点树的形式从上而下依次排列,很多同学会被迷惑,这么复杂的内容真的能用css解决吗?
其实大可不必担心,这个节点树比前面写过的轮播图和分页器都很简单。
实现中间的竖线
我们首先要实现的是中间的这条竖线,它贯穿了整个日志记录。
我们可以使用伪元素来实现,它只有边框没有内容。
<div class="container">
<article>
<h1 class="title">PbootCMS更新日志</h1>
<p class="tip">累计发布 72 个版本</p>
<ul class="log-list">
</ul>
</article>
</div>
给.log-list
添加::after
伪元素(用::before
也行):
.log-list::before {
content: "";
display: block;
height: 100%;
border-left: 0.1rem dotted var(--text-color);
position: absolute;
left: 50%;
transform: translateX(-50%);
z-index: -1;
}
这里除了基本的样式外,我们还设置了其高度为100%
用于同步容器高度,通过绝对定位将其水平居中,这里绝对定位的参照物是.log-list
:
.log-list {
position: relative;
}
这个时候由于.log-list
没有内容,因此高度为0,并不能看到效果。
实现日期与卡片
我们应该把日期+日志卡片当成一个整体,这样才能控制所有的日志格式一致。
在li标签中分别写入日期和日志卡片的容器。
<li>
<span class="date">2024-07-05</span>
<div class="box"></div>
</li>
这里我们称其为.box
,表示盒子,后面还有更加细致地内容分隔。
日期
日期的实现并不复杂,除了基本样式之外,我们只需要居中即可:
.log-list > li {
text-align: center;
margin-bottom: 2rem;
}
.log-list > li > .date {
color: #ffffff;
background-color: #28a745;
padding: 0.1rem 0.5rem;
border-radius: 0.2rem;
font-weight: bold;
margin: 0 auto;
}
由于使用的是span
标签,它是一个行内元素,父元素直接使用text-align
就可以实现居中,不需要使用flex
。
得到这样的效果:
日志卡片
日志卡片分成两个部分,分别是处于竖线的标记和日志主体,我们这样写:
<div class="box">
<div class="icon">
<i class=" iconfont icon-faxian"></i>
</div>
<div class="card left-card">
</div>
</div>
.icon
就是我们的标记,它的样式很简单:
.log-list > li > .box {
margin: 2rem 0;
position: relative;
}
.log-list > li > .box > .icon {
width: 1rem;
height: 1rem;
border-radius: 50%;
border: 0.1rem solid #28a745;
background-color: #ffffff;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
color: #28a745;
}
限定大小,然后使用margin
居中即可。
卡片的实现就比较复杂了,我们首先要考虑卡片分为左右两种形式,还得考虑左右卡片的箭头方向与位置都不一样,另外卡片距离中间竖线的方向也是相反的。
那我们应该怎么实现?
首先我们只考虑卡片样式:
.log-list > li > .box > .card {
text-align: left;
position: absolute;
width: 50%;
}
.log-list > li > .box > .card.left-card {
left: 0;
}
.log-list > li > .box > .card.right-card {
right: 0;
}
使用绝对定位,参照物为.box
元素,宽度为50%
,这样通过left和right实现左右两种形式。
接下来要实现两种不同的对齐方式,也就是与中间竖线如何对齐。我们这样写:
.log-list > li > .box > .card > .wrapper {
border: 1px solid var(--text-color);
border-radius: 0.2rem;
padding: 0.4rem 0.6rem;
box-sizing: border-box;
margin-right: 1.2rem;
transform: translateY(-1.5rem);
}
.log-list > li > .box > .card.right-card > .wrapper {
margin-left: 1.2rem;
}
在.card
内部嵌套一层.wrapper
,.card
用来限定区域,那么.wrapper
就是真正的卡片区域,默认情况下卡片margin-right
为1.2rem
,这就是与竖线的距离,而如果是右侧卡片也就是.right-card
下的.wrapper
我们给其设置margin-left
为1.2rem
,这样就解决了竖线两侧间距问题。
另外后面还要添加箭头,为了箭头与竖线上的标记对齐,我们使用transform: translateY(-1.5rem);
做了向上的位移。
最后添加箭头,我们使用之前下载的iconfont
:
左侧.card
下加入:
<i class="arrow iconfont icon-xiayibu"></i>
右侧.right-card
加入:
<i class="arrow iconfont icon-shangyibu"></i>
样式为:
.log-list > li > .box > .card > .arrow {
position: absolute;
right: 0;
top: 0;
transform: translate(-0.7rem, -1rem);
background-color: #ffffff;
}
.log-list > li > .box > .card.right-card > .arrow {
right: auto;
left: 0;
transform: translate(0.7rem, -1rem);
background-color: #ffffff;
}
这里给图标加上白色背景,用于覆盖原来的部分边框,从视觉上实现异型图案。
再调整卡片内标题和内容样式:
.log-list > li > .box > .card .card-title {
margin-bottom: 0.5rem;
}
.log-list > li > .box > .card .card-title > a {
font-size: 0.9rem;
font-weight: bold;
color: var(--normal-color);
}
.log-list > li > .box > .card .card-content {
color: var(--text-color);
}
得到最后的结果为:
问题
我们发现,最后的结果是有问题的,样式重叠了。
产生问题的原因是,我们大量使用了定位,导致内容塌陷,无法撑起li标签的高度,导致上下两个li标签重叠,实际上问题就出在卡片向上位移与标记对齐的步骤上。
那怎么解决呢?
这就是一个BFC的问题了,最简单的方式是给li标签加上:
.log-list > li {
text-align: center;
display: flow-root;
margin-bottom: 2rem;
}
display: flow-root
的意思是生成一个块级元素盒,建立一个新的区块格式化上下文,定义格式化上下文的根元素,可以参考MDN。
问题得到解决。
最后的效果为:
其他
虽然现在有了各种各样的布局方式,我们已经很少使用定位,但是如果你想实现多个元素叠加的效果,还是只有定位能够解决你的问题。