[ 基础系列 ] - CSS 小测 03

799 阅读5分钟

系列文章

说在前面

本篇是张鑫旭老师的 CSS基础测试4 的阅后笔记。(感谢 XboxYan 的解答,堪称模板。另外还有几位同学的解答也各有亮点:yaeSakurasmaomao1996

题目

先来看看题目。

完成下图所示的布局效果,只要兼容移动端即可,效果如下:

img-00

需求:

  • 视觉还原
  • 代码友好
  • 体验良好

思路

还是老规矩,先实现最基础的,再谈优化。

这个界面乍一看有几个关键点:

  • 气泡小尾巴
  • 布局

气泡小尾巴

那么先来看看这个气泡小尾巴的实现。

在我上期的 css 小测 - 02 中提到过通过 border 来绘制三角形的原理,这里同样使用 border 来完成小尾巴的绘制。

首先把正方形画出来:

.border{
    border: 20px solid $borderColor;
}

效果如下:

img-01

从题目的图中可以看到,小气泡是具有弧度的,那么这里很明显可以使用 border-radius 来调节。

首先我们为这个元素添加大小,然后去掉其中两个相邻边的 border

.border{
    background: deeppink;
    height: 20px;
    width: 20px;
    border-width: 0px 0px 20px 20px;
}

效果如下:

img-02

现在我们让左上角具有一定的弧度:

.border{
    background: deeppink;
    height: 20px;
    width: 20px;
    border-width: 0px 0px 20px 20px;
    border-top-left-radius: 60px;
}

效果如下:

img-03

仔细观察的话,小尾巴的雏形已经出现了,我们只需要让其他部分消失即可。这里需要消除的是元素本身的背景色和底部的边框。

.border{
    background: #fff;
    height: 20px;
    width: 20px;
    border-width: 0px 0px 20px 20px;
    border-top-left-radius: 60px;
    border-bottom-color: transparent;
}

最终效果如下:

img-04

这个小尾巴,在实现好气泡之后,让它把一部分藏在气泡之下即可。

布局

关于布局在我的 css 小测 - 01 中也有提到过。

这里我们先构建 HTML,有以下几点值得注意:

  • 注意命名空间
  • 如果遇到不同性质的命名空间,可以通常有两种解决方案:
    • 使用 class,在命名上加以区分,比如 msg-item__left
    • 使用属性选择器
  • 尽量使用具有语义的标签

注意以上几点,HTML 就没什么好说的了:

<ul class="chat-list">
  <li class="chat-item">
    <img
      class="chat-avator"
      alt="head"
      src="https://tva4.sinaimg.cn/crop.0.0.750.750.180/75f2b996jw8f6zkdm7qp7j20ku0kudgr.jpg"
    />
    <div class="chat-container">
      <h3 class="chat-user">
        <span class="chat-name">提按生</span>
        <span class="chat-time">9月30日 21:47</span>
      </h3>
      <p class="chat-content">
        什么秘密,我觉得你现在跟我说什么都没有意义。
      </p>
    </div>
  </li>
  <li class="chat-item" date-chat-self>
    <img
      class="chat-avator"
      alt="head"
      src="https://tvax3.sinaimg.cn/crop.135.0.810.810.180/006LO43wly8frjay2sypvj30u00mita5.jpg"
    />
    <div class="chat-container">
      <h3 class="chat-user">
        <span class="chat-name">X优秀Y</span>
        <span class="chat-time">刚刚</span>
      </h3>
      <p class="chat-content">
        围观戏精现场
      </p>
    </div>
  </li>
</ul>

那么接下来写 css。首先,reset css 的时候,padding 并没有设置的必要,因为 htmlbody 并没有 padding,其他需要花时间细调的就先不赘述了。

html,
body {
    margin: 0;
    height: 100%;
}

.chat-list {
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: auto;
    list-style: none;
}

.chat-item {
    display: flex;
    padding: 0.4375rem;
    margin-bottom: 0.9375rem;
}

.chat-item::after {
    content: '';
    display: inline-block;
    width: 2.75rem;
}

.chat-avator {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    object-fit: cover;
}

.chat-container {
    flex: 1;
    text-align: start;
    padding: 0 0.625rem;
    overflow: hidden;
}

.chat-user {
    margin: 0;
    font-weight: normal;
    font-size: 0.8125rem;
    color: #949ead;
}

.chat-user span {
    display: inline-block;
}

.chat-time {
    padding: 0 0.5rem;
}

.chat-content {
    position: relative;
    display: inline-flex;
    background: #f2f5f9;
    border-color: #f2f5f9;
    font-size: 0.875rem;
    line-height: 1.5;
    color: #2c3038;
    padding: .6rem 1rem;
    text-align: left;
    margin: 0.3125rem 0 0;
    border-radius: 0.375rem;
}

.chat-content::before {
    content: '';
    position: absolute;
    width: 1.4rem;
    height: 1.2rem;
    top: 0;
    margin-inline-start: -3rem;
    border-top-right-radius: 40% 50%;
    border-top-left-radius: 40% 50%;
    border-left: 0.6rem solid;
    border-right: 0.6rem solid;
    border-color: inherit;
}

.chat-item[data-chat-self] .chat-content {
    background: #00afff;
    border-color: #00afff;
    color: #fff;
}

效果如下:

img-05

接下来只需要让自己发送的消息靠右并且颠倒文字顺序即可,可以通过 flex-direction 来实现,不过最好的方式是通过 direction: rtl 来改变文档流:

.chat-item[data-chat-self] {
    direction: rtl;
}

效果如下:

img-06

到这里基本就完成了整个页面的布局,想要继续优化的话,可以从自适应屏幕宽度入手,之前可以通过 js 动态计算根元素的 font-size 大小,现在使用 media 就可以实现这个效果了:

html{
    font-size: 16px;
}

@media screen and (min-width: 375px) {
    html {
        /* iPhone6 的 375px 尺寸作为 16px 基准,414px 正好 18px 大小 */
        font-size: calc(100% + 2 * (100vw - 375px) / 39);
        font-size: calc(16px + 2 * (100vw - 375px) / 39);
    }
}

@media screen and (min-width: 414px) {
    html {
        /* 414px ~ 1000px 每 100 像素宽字体增加 1px(18px ~ 22px) */
        font-size: calc(112.5% + 4 * (100vw - 414px) / 586);
        font-size: calc(18px + 4 * (100vw - 414px) / 586);
    }
}

@media screen and (min-width: 600px) {
    html {
        /* 600px ~ 1000px 每 100 像素宽字体增加 1px(20px ~ 24px) */
        font-size: calc(125% + 4 * (100vw - 600px) / 400);
        font-size: calc(20px + 4 * (100vw - 600px) / 400);
    }
}

@media screen and (min-width: 1000px) {
    html {
        /* 1000px 往后是每 100 像素增加 0.5px */
        font-size: calc(137.5% + 6 * (100vw - 1000px) / 1000);
        font-size: calc(22px + 6 * (100vw - 1000px) / 1000);
    }
}

效果如下:

img-07

可以看到,随着屏幕尺寸的减小,整体内容都在不断的变小。

结束语

这一次的小测主要考察我们的综合素质,所以并没有太多的细节可讲,这里贴一下张老师总结出来的几个关键点:

  • 基准字号使用 16px,不用其它像素值。也不用使用 100px
  • media 查询和 vw 技巧实现 html 基础尺寸动态化(无需JS)
  • 要有统一的类名命名空间,类似 chat-
  • 遇到不同性质的命名,通常两种方式
    • 类名,但是命名上明显区分,例如 chat-item__left
    • 使用属性选择器
  • 避免没必要的嵌套,百害无一益
  • 小尾巴的实现。边框+圆角,box-shadow+ 圆角,径向渐变
  • 左右对称布局的实现:direction: rtl 配合 CSS 逻辑属性
  • 不推荐使用 dl 标签,可以给每个列表增加 tabindex=0

最后 在线 Demo 在这里