春节用Div给系统挂上大红灯笼

631 阅读5分钟

PK创意闹新春,我正在参加「春节创意投稿大赛」,详情请看:春节创意投稿大赛

3.jpg

春节家家户户都会挂灯笼,产品经理说了,春节期间,咱们系统也要挂灯笼。于是在React项目中用Div画了个大红灯笼。

项目中使用了ReactlessclassNames

结构拆解

首先是灯笼结构拆解:挂灯线,灯身,灯身上口&下口,灯笼骨架线,文字,灯穗。

  // 灯身
  // 灯身上口&下口,使用灯身的:before&:after实现
  <div>
    // 挂灯线
    <div />
    // 灯笼骨架线-外层
    <div>
      // 灯笼骨架线-内层
      <div>
        <div>文字</div>
      </div>
    </div>
    // 灯穗
    <div>
      // 灯穗线
      <div />
      <div />
    </div>
  </div>

灯笼样式

html结构加上class,这里使用到了classNames,请自行install,如果不想用可以自行修改。

  // 灯身
  <div className={styles.deng}>
    // 挂灯线
    <div className={styles.xian} />
    // 灯笼骨架线-外层
    <div className={classNames(styles.arc, styles.arcA)}>
      // 灯笼骨架线-内层
      <div className={classNames(styles.arc, styles.arcB)}>
        // 文字
        <div className={styles.dengTxt}></div>
      </div>
    </div>
    // 灯穗
    <div className={styles.sui}>
      // 灯穗线
      <div className={styles.sui1} />
      <div className={styles.sui2} />
    </div>
  </div>

接下来就是调整css样式,灯笼大小采用固定宽高,主要css如下。

灯身

border-radius圆形,红色背景,再用box-shadow加上朦胧灯光效果。

  .deng {
    position: relative;
    width: 120px;
    height: 90px;
    margin: 30px;
    background: #d8000f;
    background: rgba(216, 0, 15, 0.8);
    border-radius: 50% 50%;
    // 灯笼的灯光效果
    box-shadow: -5px 5px 50px 4px rgba(250, 108, 0, 1);
  }

挂灯线

宽高调整粗细,背景色控制颜色,绝对定位控制位置。

  .xian {
    position: absolute;
    top: -30px;
    left: 60px;
    width: 2px;
    height: 30px;
    background: #dc8f03;
  }

灯笼骨架线

border控制粗细和颜色。

  .arc {
    height: 90px;
    background: rgba(216, 0, 15, 0.1);
    border-radius: 50% 50%;
    border: 2px solid #dc8f03;
  }
  • 灯笼骨架线-外层 宽度控制位置。。
  .arcA {
    width: 100px;
    margin: 12px 8px 8px 10px;
  }
  • 灯笼骨架线-内层 宽度控制位置。
  .arcB {
    width: 45px;
    margin: -2px 8px 8px 26px;
  }

文字

应该也可以替换成图片,感兴趣的同学可以自行尝试。

  .dengTxt {
    font-family: Arial, Lucida Grande, Tahoma, sans-serif;
    font-size: 3.2rem;
    color: #dc8f03;
    font-weight: bold;
    line-height: 85px;
    text-align: center;
  }

灯穗

  .sui {
    position: relative;
    width: 5px;
    height: 20px;
    margin: -5px 0 0 59px;
    background: #ffa500;
    border-radius: 0 0 5px 5px;
  }
  • 灯穗线
  .sui1 {
    position: absolute;
    top: 18px;
    left: -2px;
    width: 10px;
    height: 35px;
    background: #ffa500;
    border-radius: 0 0 0 5px;
  }
  .sui2 {
    position: absolute;
    top: 14px;
    left: -2px;
    width: 10px;
    height: 10px;
    background: #dc8f03;
    border-radius: 50%;
  }

灯身上口

  .deng:before {
    position: absolute;
    top: -7px;
    left: 29px;
    height: 12px;
    width: 60px;
    content: ' ';
    display: block;
    z-index: 999;
    border-radius: 5px 5px 0 0;
    border: solid 1px #dc8f03;
    background: #ffa500;
    background: linear-gradient(to right, #dc8f03, #ffa500, #dc8f03, #ffa500, #dc8f03);
  }

灯身下口

  .deng:after {
    position: absolute;
    bottom: -7px;
    left: 10px;
    height: 12px;
    width: 60px;
    content: ' ';
    display: block;
    margin-left: 20px;
    border-radius: 0 0 5px 5px;
    border: solid 1px #dc8f03;
    background: #ffa500;
    background: linear-gradient(to right, #dc8f03, #ffa500, #dc8f03, #ffa500, #dc8f03);
  }

1.jpg

灯笼画好了,什么,不会动,风一吹要让它动起来,安排,那就使用animation+transform给灯笼加上动效。

动效

摆动动效css

  @keyframes swing {
    0% {
      transform: rotate(-10deg);
    }

    50% {
      transform: rotate(10deg);
    }

    100% {
      transform: rotate(-10deg);
    }
  }

给灯和灯穗加上动效。

  .deng {
    transform-origin: 50% -100px;
    animation: swing 3s infinite ease-in-out;
  }
  .sui {
    transform-origin: 50% -45px;
    animation: swing 4s infinite ease-in-out;
  }

没录制动图,请自行想象。

2-1.jpg 2-2.jpg

一个灯笼有点单调,多挂几个,直接复制前面的结构即可,样式大部分可以复用。

再将所有灯笼包起来,使用绝对定位调整每个灯笼的位置,再修改下每个灯笼的动效时间,制造伪随机的晃动。

最终的成品效果如下。 3.jpg

完整代码如下。

  • html部分。
    <div className={classNames(styles.dengBox, styles.dengBox1)}>
        <div className={styles.deng}>
          <div className={styles.xian} />
          <div className={classNames(styles.arc, styles.arcA)}>
            <div className={classNames(styles.arc, styles.arcB)}>
              <div className={styles.dengTxt}></div>
            </div>
          </div>
          <div className={styles.sui}>
            <div className={styles.sui1} />
            <div className={styles.sui2} />
          </div>
        </div>
      </div>

      <div className={classNames(styles.dengBox, styles.dengBox2)}>
        <div className={styles.deng}>
          <div className={styles.xian} />
          <div className={classNames(styles.arc, styles.arcA)}>
            <div className={classNames(styles.arc, styles.arcB)}>
              <div className={styles.dengTxt}></div>
            </div>
          </div>
          <div className={styles.sui}>
            <div className={styles.sui1} />
            <div className={styles.sui2} />
          </div>
        </div>
      </div>

      <div className={classNames(styles.dengBox, styles.dengBox3)}>
        <div className={styles.deng}>
          <div className={styles.xian} />
          <div className={classNames(styles.arc, styles.arcA)}>
            <div className={classNames(styles.arc, styles.arcB)}>
              <div className={styles.dengTxt}></div>
            </div>
          </div>
          <div className={styles.sui}>
            <div className={styles.sui1} />
            <div className={styles.sui2} />
          </div>
        </div>
      </div>

      <div className={classNames(styles.dengBox, styles.dengBox4)}>
        <div className={styles.deng}>
          <div className={styles.xian} />
          <div className={classNames(styles.arc, styles.arcA)}>
            <div className={classNames(styles.arc, styles.arcB)}>
              <div className={styles.dengTxt}></div>
            </div>
          </div>
          <div className={styles.sui}>
            <div className={styles.sui1} />
            <div className={styles.sui2} />
          </div>
        </div>
      </div>
  • css部分。
 @keyframes swing {
    0% {
      transform: rotate(-10deg);
    }

    50% {
      transform: rotate(10deg);
    }

    100% {
      transform: rotate(-10deg);
    }
  }

  .dengBox {
    position: absolute;
    top: 0px;
    z-index: 9999;
    pointer-events: none;
    .deng {
      position: relative;
      width: 120px;
      height: 90px;
      margin: 30px;
      background: #d8000f;
      background: rgba(216, 0, 15, 0.8);
      border-radius: 50% 50%;
      box-shadow: -5px 5px 50px 4px rgba(250, 108, 0, 1);
      transform-origin: 50% -100px;
      animation: swing 3s infinite ease-in-out;
    }
    .xian {
      position: absolute;
      top: -30px;
      left: 60px;
      width: 2px;
      height: 30px;
      background: #dc8f03;
    }
    .arc {
      height: 90px;
      background: rgba(216, 0, 15, 0.1);
      border-radius: 50% 50%;
      border: 2px solid #dc8f03;
    }
    .arcA {
      width: 100px;
      margin: 12px 8px 8px 10px;
    }

    .arcB {
      width: 45px;
      margin: -2px 8px 8px 26px;
    }

    .dengTxt {
      font-family: Arial, Lucida Grande, Tahoma, sans-serif;
      font-size: 3.2rem;
      color: #dc8f03;
      font-weight: bold;
      line-height: 85px;
      text-align: center;
    }

    .sui {
      position: relative;
      width: 5px;
      height: 20px;
      margin: -5px 0 0 59px;
      background: #ffa500;
      border-radius: 0 0 5px 5px;
      transform-origin: 50% -45px;
      animation: swing 4s infinite ease-in-out;
    }
    .sui1 {
      position: absolute;
      top: 18px;
      left: -2px;
      width: 10px;
      height: 35px;
      background: #ffa500;
      border-radius: 0 0 0 5px;
    }
    .sui2 {
      position: absolute;
      top: 14px;
      left: -2px;
      width: 10px;
      height: 10px;
      background: #dc8f03;
      border-radius: 50%;
    }

    .deng:before {
      position: absolute;
      top: -7px;
      left: 29px;
      height: 12px;
      width: 60px;
      content: ' ';
      display: block;
      z-index: 999;
      border-radius: 5px 5px 0 0;
      border: solid 1px #dc8f03;
      background: #ffa500;
      background: linear-gradient(to right, #dc8f03, #ffa500, #dc8f03, #ffa500, #dc8f03);
    }

    .deng:after {
      position: absolute;
      bottom: -7px;
      left: 10px;
      height: 12px;
      width: 60px;
      content: ' ';
      display: block;
      margin-left: 20px;
      border-radius: 0 0 5px 5px;
      border: solid 1px #dc8f03;
      background: #ffa500;
      background: linear-gradient(to right, #dc8f03, #ffa500, #dc8f03, #ffa500, #dc8f03);
    }
  }
  .dengBox1 {
    left: 60px;
    .deng {
      animation: swing 3s infinite ease-in-out;
      box-shadow: -5px 5px 50px 4px rgba(250, 108, 0, 1);
    }
  }

  .dengBox2 {
    left: 120px;
    .deng {
      animation: swing 4s infinite ease-in-out;
      box-shadow: -5px 5px 30px 4px rgba(252, 144, 61, 1);
    }
  }

  .dengBox3 {
    right: 60px;
    .deng {
      animation: swing 5s infinite ease-in-out;
      box-shadow: -5px 5px 50px 4px rgba(250, 108, 0, 1);
    }
  }

  .dengBox4 {
    right: 120px;
    .deng {
      animation: swing 4s infinite ease-in-out;
      box-shadow: -5px 5px 30px 4px rgba(252, 144, 61, 1);
    }
  }

以上其实是htmlcss就可以实现的,所以如果不是React的项目也是可以移植的。以上代码中css并没有做兼容性处理,移植时需要注意。

好了,灯笼就到这里了。 春节还搞了个烟花,参见春节放# 春节用JS在系统里放烟花