CSS动画小剧场:两个小球的浪漫邂逅

160 阅读7分钟

引子:一场HTML与CSS的爱情故事

各位看官,今天我们要讲一个关于网页世界的浪漫故事。主角是两个可爱的小球——左球和右球(别笑,这名字可是他们自己选的)。他们的爱情故事,将用最优雅的HTML和CSS语言来讲述。在此过程中顺带给大家介绍一下重要考点(哈哈哈其实这才是主角)

第一幕:初遇 - HTML结构搭建

让我们先认识一下两位主角:

<!-- 包裹两个小球的大盒子 -->
    <div class="container">
        <!-- 左球 -->
        <div id="l-ball" class="ball">
            <!-- 左球脸 -->
            <div class="face face-l">
                <!-- 眼睛,嘴巴 -->
                <div class="eye eye-l"></div>
                <div class="eye eye-r"></div>
                <div class="mouth"></div>
            </div>
        </div>

        <!-- 右球 -->
        <div id="r-ball" class="ball">
            <!-- 右球脸 -->
            <div class="face face-r">
                <!-- 眼睛,嘴巴 -->
                <div class="eye eye-l eye-r-p"></div>
                <div class="eye eye-r eye-r-p"></div>
                <div class="mouth mouth-r"></div>
            </div>
        </div>
    </div>

这段代码里藏着不少秘密:

  • div.container 是我们为这场爱情故事搭建的舞台
  • #l-ball 和 #r-ball 分别是左球和右球的ID(就像他们的身份证)
  • .ball 是他们共同的名字,说明他们有着相同的特征

这个写法用到了Emmet语法,是不是很像魔法咒语?.container>#l-ball.ball+#r-ball.ball,念完就变出了一个完美的舞台!(再按照类型的操作,生成小球里面的小盒子)

第二幕:妆容 - CSS基础样式

每个浪漫的故事都需要美丽的装扮:

<style>
        /* 给小球添加一个浪漫的粉色背景舞台 */
        body {
            background-color: pink;
            margin: 0;

        }

        /* 给大盒子添加属性 */
        .container {
            position: absolute;
            top: 50%;
            left: 50%;
            width: 238px;
            /*被内容撑高就好*/
            /* height: 238px; */
            /*背景颜色大法*/
            /* background-color: blue; */

            /* 与top 50%,left %50 共同完成了是其达到舞台中央 */
            transform: translate(-50%, -50%);
        }

        .ball {
            width: 100px;
            height: 100px;
            border: 8px solid black;
            /*将盒子改成圆形*/
            border-radius: 50%;
            display: inline-block;
            background-color: white;
            /*行内块元素贴于舞台顶部*/
            vertical-align: top;
            /* 相对定位,子元素相对它定位 */
            position: relative;
        }

        .face {
            width: 70px;
            height: 30px;
            position: absolute;
            right: 0;
            top: 30px;
            border-top-right-radius: 15px;
            /* background-color: green; */

        }

        .eye {
            width: 15px;
            height: 15px;
            border-radius: 50%;
            border-bottom: 5px solid black;
            position: absolute;

        }

        .eye-l {
            position: absolute;
            left: 10px;
        }

        .eye-r {
            position: absolute;
            right: 5px;
        }

        .mouth {
            width: 30px;
            height: 14px;
            border-radius: 50%;
            border-bottom: 5px solid black;
            position: absolute;
            bottom: -5px;
            transform: translate(3px);
            left: 0;
            right: 0;
            margin: auto;
        }

        .eye-r-p {
            border-top: 5px solid black;
            border-bottom: none;
        }
    </style>

是不是太多了,没事,接下来给大家解释一下重点

第三幕:约会 - 定位的艺术

为了让两颗心更靠近,我们需要懂点定位技巧:

.container {
            position: absolute;
            top: 50%;
            left: 50%;
            width: 238px;
            /*被内容撑高就好*/
            /* height: 238px; */
            /*背景颜色大法*/
            /* background-color: blue; */

            /* 与top 50%,left %50 共同完成了是其达到舞台中央 */
            transform: translate(-50%, -50%);
        }

这里面可有不少门道:

  • position: absolute 让我们的舞台可以自由移动
  • top: 50%; left: 50% 把舞台中心移到屏幕正中(是盒子的左上角移至页面中心点,top从上往下,left是从左往右)
  • transform: translate(-50%, -50%) 这个有点难理解,但记住它是居中的终极武器(意思是盒子往左移50%的盒子宽度,往上移%50的盒子高度,与top: 50%; left: 50%组合一起就能实现盒子再“舞台的居中”)
  • margin-left 让右球害羞地往旁边挪了挪

为了更好的理解居中,我来画个图

image.png

什么是定位

我们来讲一下相对定位,和绝对定位

绝对定位

absolute 绝对定位 相对于最近的定位父元素 absolute 找到离它(管着它的)最近的position 不为static 的属性定位 直到body为止

简单来说就是参考的是距离最近的有定位的祖先元素,如果所有的祖先元素都没有设置定位,则参考body。

参考以下代码

  <style>
        *{
            margin: 0;
            padding: 0;
        }
        .box1{
            width: 400px;
            height: 400px;
            border: 5px solid red;
            margin: 100px auto;
            position: relative;
        }
        .box2{
            width: 300px;
            height: 300px;
            border: 5px solid green;
            position: absolute;
            left: 50px;
            top: 50px;
        }
        .box3{
            width: 200px;
            height: 200px;
            border: 5px solid blue;
            position: absolute;
            left: 50px;
            top: 50px;
        }
        p{
            width: 50px;
            height: 50px;
            background-color: gold;
            position: absolute;
            left: 50px;
            top: 50px;
        }
    </style>
</head>
<body>
    <div class="box1">
        <div class="box2">
            <div class="box3">
                <p></p>
            </div>
        </div>
    </div>
</body>

都是参考离最近的祖先元素的position,p参考.box3;.box3参考.box2;.box2参考.box1,假设.box3和.box2都没有不为static的position,p就会参考.box1 image.png 当把所有的position注释掉,只保留p的相对定位,就会参考整个body页面

image.png

相对定位

  • 子元素相对它定位

其实就是绝对定位,去寻找祖先元素的定位

  • 相对于自身的位置定位

参考自身原位置,所移动,定位

<style>
        *{
            margin: 0;
            padding: 0;
        }
        div{
            width: 300px;
            margin: 100px auto;

        }
        p{
            width: 100px;
            height: 100px;
            background-color: cyan;
            margin: 5px;

        }
        p.current{
            background-color: green;
            position: relative;
            left: 100px;
            bottom: 100px;
        }

    </style>
</head>
<body>
    <div>
        <p></p>
        <p class="current"></p>
        <p></p>
    </div>
</body>

相对于原来的位置所移动 image.png

第四章:让我们相遇

两个小球的div盒子标签,都是块级标签,那么我们如何使其在一行显示呢,介绍这个之前,我们先来简单的了解一下行内元素和块级元素

行内元素 span,i a inline 行内元素 不独占一行 不可以设置宽高

块级元素div p独占一行 可以设置宽高

这就需要通过我们的display属性了

display:相遇之法

display 切换行内块的格式化上下文能力 简单来说就是可以把块级元素设置为行内元素,行内元素设置为块级元素,还有两者兼具的行内块元素

  • inline 行内 不可以设置宽高
  <style>
    div{
      width: 200px;
      height: 200px;
      margin: 20px;
      background-color: green;
      display: inline; 
    }
  </style>
</head>
<body>
  <div>我是div1标签</div>
  <div>我是div2标签</div>

可以看到我们的块级元素变成了行内块元素 image.png

  • block 块级 独占一行 可以设置宽高
<style>
    span {
      background-color: pink;
      padding: 20px;
      display: block;
      height: 100px;
      width: 100px;
    }
  </style>
</head>

<body>
  <span>文字1</span>
  <span>文字2</span>
</body>

行内块元素变成了块级元素可以设置宽高行高 image.png

  • inline-block 行内块元素 在一行 可以设置宽高
<style>
    div{
      width: 200px;
      height: 200px;
      margin: 20px;
      background-color: green;
      display: inline-block;
    }
  </style>
</head>
<body>
  <div>我是div1标签</div>
  <div>我是div2标签</div>
</body>

既可以设置宽高,又可以在一行内显示 image.png

第五章:樱桃小嘴,卡姿兰大眼

.eye {
            width: 15px;
            height: 15px;
            border-radius: 50%;
            border-bottom: 5px solid black;
            position: absolute;

        }
.mouth {
            width: 30px;
            height: 14px;
            border-radius: 50%;
            border-bottom: 5px solid black;
            position: absolute;
            bottom: -5px;
            transform: translate(3px);
            left: 0;
            right: 0;
            margin: auto;
        }

border-radius: 50%; 把盒子改成圆形,由于我们并没有添加颜色背景,看不出来眼睛,这个时候我们来border-bottom: 5px solid black;添加了一个底边框,我们就能看到下边部分的圆弧形,相当于“卡姿兰大眼”,需要向上弯曲就设置为border-top5px solid black;

image.png

嘴巴也是同理

image.png

transform: translate(3px);

是一个 CSS 变换属性的应用,用于在网页上移动元素。不过,这里有一个小点需要注意:通常 translate 函数需要两个参数来分别指定在X轴(水平方向)和Y轴(垂直方向)上的位移值。当只提供一个参数时,这个值默认应用于X轴,而Y轴的位移则为0。

所以,当你写 transform: translate(3px);,实际上它等同于 transform: translate(3px, 0);,这意味着元素将仅沿水平方向向右移动3个像素,垂直位置不变。

尾声:写给前端开发者的启示

亲爱的开发者们,这个简单的故事背后蕴含着深刻的道理:

  1. 选择器就是缘分:ID和class的选择,就像人生中遇到的各种人,有些注定是过客,有些则是命中注定
  2. 定位是成长的过程:relative让我们看到自己的价值,absolute教会我们如何找到归宿

image.png

所以,下次当你写下一行CSS代码时,不妨想象这是一个正在发生的故事。毕竟,在这个数字时代,还有什么比创造美更浪漫的事呢?

祝所有代码都能成功运行,所有爱情都能圆满结局!

image.png