Skip to content
本页目录

css 奶油风格小组件

核心实现在于box-shadow 阴影的控制和背景色的选择

Switch

<script lang='ts' setup>

</script>

<template>
  <div class="custom-wrapper p-10">
    <div class="container px-12 py-6 rounded-10px">
      <div class="milk-switch w-24 inline-block mr-12">
        <input id="switch-1" type="checkbox" class="display-none">
        <label for="switch-1" class="inline-block w-full h-12 cursor-pointer rounded-6 relative flex items-center" />
      </div>
      <div class="milk-switch w-24 inline-block">
        <input id="switch-2" type="checkbox" class="display-none" checked>
        <label for="switch-2" class="inline-block w-full h-12 cursor-pointer rounded-6 relative flex items-center" />
      </div>
    </div>
  </div>
</template>

<style lang='scss' scoped>
  .custom-wrapper {
    --primary-light: #8abdff;
    --primary: #6d5dfc;
    --primary-dark: #5b0eeb;

    --white: #FFFFFF;
    --greyLight-1: #E4EBF5;
    --greyLight-2: #c8d0e7;
    --greyLight-3: #bec8e4;
    --greyDark: #9baacf;

    $shadow: .3rem .3rem .6rem var(--greyLight-2), -.2rem -.2rem .5rem var(--white);
    $inner-shadow: inset .2rem .2rem .5rem var(--greyLight-2), inset -.2rem -.2rem .5rem var(--white);

    background-color: var(--greyLight-1);

    .container {
      box-shadow:.8rem .8rem 1.4rem var(--greyLight-2), -.2rem -.2rem 1.8rem var(--white);
      .milk-switch {
        label {
          box-shadow: $shadow;
          &::after {
            content: '';
            position: absolute;
            left: .4rem;
            width: 2.1rem;
            height: 2.1rem;
            border-radius: 50%;
            background-color: var(--greyDark);
            transition: all 0.4s ease;
          }

          &::before {
            content: '';
            width: 100%;
            height: 100%;
            border-radius: inherit;
            background: linear-gradient(330deg, var(--primary-dark) 0%, var(--primary) 50%, var(--primary-light) 100%);
            opacity: 0;
            transition: all .4s ease;
          }
        }
        & input:checked {
          & ~ label {
            &::before { opacity: 1; }
            &::after {
              left: 57%;
              background: var(--greyLight-1);
            }
          }
        }
      }
    }
  }
</style>

Checkbox

<script lang='ts' setup>

</script>

<template>
  <div class="custom-wrapper p-10">
    <div class="container px-12 py-6 rounded-10px">
      <div class="checkbox w-24 inline-block mr-12">
        <input id="checkbox-1" type="checkbox" class="display-none">
        <label for="checkbox-1" class="flex items-center w-12 h-12 justify-center rounded-6">
          <i class="i-ri:check-line">done</i></label>
      </div>
      <div class="checkbox w-24 inline-block">
        <input id="checkbox-2" type="checkbox" class="display-none" checked>
        <label for="checkbox-2" class="flex items-center w-12 h-12 justify-center rounded-6">
          <i class="i-ri:check-line">done</i></label>
      </div>
    </div>
  </div>
</template>

<style lang='scss' scoped>
  .custom-wrapper {
    --primary-light: #8abdff;
    --primary: #6d5dfc;
    --primary-dark: #5b0eeb;

    --white: #FFFFFF;
    --greyLight-1: #E4EBF5;
    --greyLight-2: #c8d0e7;
    --greyLight-3: #bec8e4;
    --greyDark: #9baacf;

    $shadow: .3rem .3rem .6rem var(--greyLight-2), -.2rem -.2rem .5rem var(--white);
    $inner-shadow: inset .2rem .2rem .5rem var(--greyLight-2), inset -.2rem -.2rem .5rem var(--white);

    background-color: var(--greyLight-1);

    .container {
      box-shadow:.8rem .8rem 1.4rem var(--greyLight-2), -.2rem -.2rem 1.8rem var(--white);
      .checkbox {
        label {
          box-shadow: $shadow;
          i {
            font-size: 1.8rem;
            font-weight: bold;
            color: var(--greyDark);
            transition: all 0.3s ease;
          }

          &:hover i {
            color: var(--primary);
          }
        }
        & input:checked {
          & ~ label {
            box-shadow: $inner-shadow;
            i {
              color: var(--primary);
            }
          }
        }
      }
    }
  }
</style>

Radio

<script lang='ts' setup>

</script>

<template>
  <div class="custom-wrapper p-10">
    <div class="container px-12 py-6 rounded-10px">
      <div class="w-24 inline-block mr-12">
        <input id="radio-1" type="radio" name="radio" value="1" class="display-none">
        <label for="radio-1" class="relative flex justify-center items-center cursor-pointer w-12 h-12 rounded-6" />
      </div>

      <div class="w-24 inline-block">
        <input id="radio-2" type="radio" name="radio" value="2" checked class="display-none">
        <label for="radio-2" class="relative flex justify-center items-center cursor-pointer w-12 h-12 rounded-6" />
      </div>
    </div>
  </div>
</template>

<style lang='scss' scoped>
  .custom-wrapper {
    --primary-light: #8abdff;
    --primary: #6d5dfc;
    --primary-dark: #5b0eeb;

    --white: #FFFFFF;
    --greyLight-1: #E4EBF5;
    --greyLight-2: #c8d0e7;
    --greyLight-3: #bec8e4;
    --greyDark: #9baacf;

    $shadow: .3rem .3rem .6rem var(--greyLight-2), -.2rem -.2rem .5rem var(--white);
    $inner-shadow: inset .2rem .2rem .5rem var(--greyLight-2), inset -.2rem -.2rem .5rem var(--white);

    background-color: var(--greyLight-1);

    .container {
      box-shadow:.8rem .8rem 1.4rem var(--greyLight-2), -.2rem -.2rem 1.8rem var(--white);
      label {
        box-shadow: $shadow;
        &::after {
          content: '';
          position: absolute;
          width: 1.4rem;
          height: 1.4rem;
          border-radius: 50%;
          background-color: var(--greyDark);
          transition: all 0.4s ease;
        }
      }
      & input:checked {
        & ~ label {
          box-shadow: $inner-shadow;
          &::after {
            background: var(--primary);
          }
        }
      }
    }
  }
</style>

Button

<script lang='ts' setup>

</script>

<template>
  <div class="custom-wrapper p-10">
    <div class="container px-12 py-6 rounded-10px">
      <div class="btn btn__primary w-60 h-16 rounded-4 flex items-center justify-center transition-all duration-300 ease select-none cursor-pointer mr-6 mb-6">
        <span class="text-lg font-bold">
          Button
        </span>
      </div>
      <div class="btn btn__secondary w-60 h-16 rounded-4 flex items-center justify-center transition-all duration-300 ease select-none cursor-pointer">
        <span class="text-lg font-bold">
          Button
        </span>
      </div>
    </div>
  </div>
</template>

<style lang='scss' scoped>
  .custom-wrapper {
    --primary-light: #8abdff;
    --primary: #6d5dfc;
    --primary-dark: #5b0eeb;

    --white: #FFFFFF;
    --greyLight-1: #E4EBF5;
    --greyLight-2: #c8d0e7;
    --greyLight-3: #bec8e4;
    --greyDark: #9baacf;

    $shadow: .3rem .3rem .6rem var(--greyLight-2), -.2rem -.2rem .5rem var(--white);
    $inner-shadow: inset .2rem .2rem .5rem var(--greyLight-2), inset -.2rem -.2rem .5rem var(--white);

    background-color: var(--greyLight-1);

    .container {
      box-shadow:.8rem .8rem 1.4rem var(--greyLight-2), -.2rem -.2rem 1.8rem var(--white);
      .btn {
        box-shadow: $shadow;
        &__primary {
          background-color: var(--primary);
          box-shadow:inset .2rem .2rem 1rem var(--primary-light), inset -.2rem -.2rem 1rem var(--primary-dark), $shadow;
          color: var(--greyLight-1);
          &:hover { color: var(--white); }
          &:active {
            box-shadow:inset .2rem .2rem 1rem var(--primary-dark), inset -.2rem -.2rem 1rem var(--primary-light);
          }
        }
        &__secondary {
          color: var(--greyDark);
          &:hover { color: var(--primary); }
          &:active {
            box-shadow: $inner-shadow;
          }
        }
      }
    }
  }
</style>

Tab

<script lang='ts' setup>

</script>

<template>
  <div class="custom-wrapper p-10">
    <div class="container px-12 py-6 rounded-10px">
      <div class="segmented-control w-full h-16 rounded-4 flex items-center relative px-2">
        <input id="tab-1" class="display-none" type="radio" name="radio2" value="3" checked>
        <label for="tab-1" class="segmented-control__1 flex-1 h-14 text-lg flex items-center justify-center cursor-pointer transition-all duration-500 ease">
          <p>Tab 1</p></label>

        <input id="tab-2" class="display-none" type="radio" name="radio2" value="4">
        <label for="tab-2" class="segmented-control__2 flex-1 h-14 text-lg flex items-center justify-center cursor-pointer transition-all duration-500 ease">
          <p>Tab 2</p></label>

        <input id="tab-3" class="display-none" type="radio" name="radio2" value="5">
        <label for="tab-3" class="segmented-control__3 flex-1 h-14 text-lg flex items-center justify-center cursor-pointer transition-all duration-500 ease">
          <p>Tab 3</p></label>

        <div class="segmented-control__color h-12 rounded-3.2 absolute left-2 transition-transform duration-300 ease" />
      </div>
    </div>
  </div>
</template>

<style lang='scss' scoped>
  .custom-wrapper {
    --primary-light: #8abdff;
    --primary: #6d5dfc;
    --primary-dark: #5b0eeb;

    --white: #FFFFFF;
    --greyLight-1: #E4EBF5;
    --greyLight-2: #c8d0e7;
    --greyLight-3: #bec8e4;
    --greyDark: #9baacf;

    $shadow: .3rem .3rem .6rem var(--greyLight-2), -.2rem -.2rem .5rem var(--white);
    $inner-shadow: inset .2rem .2rem .5rem var(--greyLight-2), inset -.2rem -.2rem .5rem var(--white);

    background-color: var(--greyLight-1);

    .container {
      box-shadow:.8rem .8rem 1.4rem var(--greyLight-2), -.2rem -.2rem 1.8rem var(--white);
      .segmented-control {
        box-shadow: $shadow;
        input:checked + label {
          transition: all 0.5s ease;
          color: var(--primary);
          font-weight: bold;
        }
        label {
          color: var(--greyDark);
          &:hover {
            color: var(--primary);
            font-weight: bold;
          }
        }
        &__color {
          box-shadow: $inner-shadow;
          pointer-events: none;
          width: calc(calc(100% - 1rem) / 3);
        }

        #tab-1:checked ~ .segmented-control__color {
          transform: translateX(0);
        }
        #tab-2:checked ~ .segmented-control__color {
          transform: translateX(100%);
        }
        #tab-3:checked ~ .segmented-control__color {
          transform: translateX(200%);
        }
      }

    }
  }
</style>

Input

<script lang='ts' setup>

</script>

<template>
  <div class="custom-wrapper p-10">
    <div class="container px-12 py-6 rounded-10px">
      <div class="form mb-12">
        <input type="text" class="form__input w-80 h-16 border-none rounded-4 px-6 bg-none " placeholder="请输入...">
      </div>

      <div class="search relative flex items-center">
        <input type="text" class="search__input w-80 h-16 border-none rounded-4 pl-12 pr-6 bg-none " placeholder="查询...">
        <span class="i-ic:round-search absolute text-8 left-3 transition-color duration-300 ease" />
      </div>
    </div>
  </div>
</template>

<style lang='scss' scoped>
  .custom-wrapper {
    --primary-light: #8abdff;
    --primary: #6d5dfc;
    --primary-dark: #5b0eeb;

    --white: #FFFFFF;
    --greyLight-1: #E4EBF5;
    --greyLight-2: #c8d0e7;
    --greyLight-3: #bec8e4;
    --greyDark: #9baacf;

    $shadow: .3rem .3rem .6rem var(--greyLight-2), -.2rem -.2rem .5rem var(--white);
    $inner-shadow: inset .2rem .2rem .5rem var(--greyLight-2), inset -.2rem -.2rem .5rem var(--white);

    background-color: var(--greyLight-1);

    .container {
      box-shadow:.8rem .8rem 1.4rem var(--greyLight-2), -.2rem -.2rem 1.8rem var(--white);
      input {
        box-shadow: $inner-shadow;
        color: var(--greyDark);
        &::placeholder {
          color: var(--greyLight-3);
        }
        &:focus {
          outline: none;
          box-shadow: $shadow;
        }
      }

      .search {
        span {
          color: var(--greyDark);
        }
        input:focus {
          outline: none;
          box-shadow: $shadow;
          & + span {
            color: var(--primary)
          }
        }
      }
    }
  }
</style>

Alert

<script lang='ts' setup>

</script>

<template>
  <div class="custom-wrapper p-10">
    <div class="container px-12 py-6 rounded-10px">
      <div class="alert w-full flex items-center h-16 rounded-4 justify-between justify-self-center">
        <div class="p-4 text-xl font-bold icon-left">
          <span class="i-gis:color" />
        </div>
        <p class="flex-1 text-lg px-2 m-0">
          some tips.....
        </p>
        <div class="p-4 text-xl font-bold icon-right cursor-pointer">
          <span class="i-iconamoon:close-light" />
        </div>
      </div>
    </div>
  </div>
</template>

<style lang='scss' scoped>
  .custom-wrapper {
    --primary-light: #8abdff;
    --primary: #6d5dfc;
    --primary-dark: #5b0eeb;

    --white: #FFFFFF;
    --greyLight-1: #E4EBF5;
    --greyLight-2: #c8d0e7;
    --greyLight-3: #bec8e4;
    --greyDark: #9baacf;

    $shadow: .3rem .3rem .6rem var(--greyLight-2), -.2rem -.2rem .5rem var(--white);
    $inner-shadow: inset .2rem .2rem .5rem var(--greyLight-2), inset -.2rem -.2rem .5rem var(--white);

    background-color: var(--greyLight-1);

    .container {
      box-shadow:.8rem .8rem 1.4rem var(--greyLight-2), -.2rem -.2rem 1.8rem var(--white);
      .alert {
        box-shadow: $shadow;
        .icon-left {
          color: var(--primary);
        }
        p {
          color: var(--greyDark);
        }
        .icon-right {
          color: var(--greyDark);
        }
      }

    }
  }
</style>

Slider

<script lang='ts' setup>
import { ref } from 'vue'

const rangeValue = ref(50)
const sliderBox = ref()
const sliderBtn = ref()
const sliderColor = ref()
const sliderTooltip = ref()
</script>

<template>
  <div class="custom-wrapper pt-10 px-10 pb-20">
    <div class="slider flex self-center flex-col">
      <div ref="sliderBox" class="slider__box w-full h-4 cursor-pointer relative flex justify-center items-center rounded-4">
        <span ref="sliderBtn" class="slider__btn pointer-events-none w-8 h-8 rounded-4 absolute z-100 flex items-center justify-center translate-x--4" :style="{ left: `${rangeValue}%` }" />
        <span ref="sliderColor" class="slider__color h-full absolute left-0 z-50 rounded-inherit" :style="{ width: `${rangeValue}%` }" />
        <span ref="sliderTooltip" class="slider__tooltip absolute top-10 h-10 w-12 rounded-2 flex items-center justify-center text-lg opacity-0 transition-opacity duration-300 ease translate-x--6" :style="{ left: `${rangeValue}%` }">{{ `${rangeValue}%` }}</span>
        <input v-model="rangeValue" type="range" class="w-full absolute left-0 top-0 z-300 border-none m-0 opacity-0" :min="0" :max="100">
      </div>
    </div>
  </div>
</template>

<style lang='scss' scoped>
  .custom-wrapper {
    --primary-light: #8abdff;
    --primary: #6d5dfc;
    --primary-dark: #5b0eeb;

    --white: #FFFFFF;
    --greyLight-1: #E4EBF5;
    --greyLight-2: #c8d0e7;
    --greyLight-3: #bec8e4;
    --greyDark: #9baacf;

    $shadow: .3rem .3rem .6rem var(--greyLight-2), -.2rem -.2rem .5rem var(--white);
    $inner-shadow: inset .2rem .2rem .5rem var(--greyLight-2), inset -.2rem -.2rem .5rem var(--white);

    background-color: var(--greyLight-1);

    .slider {
      &__box {
        box-shadow: $inner-shadow;
      }
      &__btn {
        background-color: var(--white);
        box-shadow: 0px .1rem .3rem 0px var(--greyLight-3);
        &::after {
          content: '';
          position: absolute;
          width: .8rem;
          height: .8rem;
          border-radius: 50%;
          box-shadow: $inner-shadow;
        }
      }
      &__color {
        background: var(--primary);
        background: linear-gradient(-1deg, var(--primary-dark) 0%, var(--primary) 50%, var(--primary-light) 100%);
      }
      &__tooltip {
        color: var(--primary);
        box-shadow: $shadow;
      }

      &:hover .slider__tooltip {opacity: 1;}

    }
  }
</style>

Icon Button

<script lang='ts' setup>

</script>

<template>
  <div class="custom-wrapper p-10">
    <div class="container py-4 px-8 rounded-4 flex items-center">
      <div class="icon-item w-16 h-16 rounded-8 flex items-center justify-center text-8 cursor-pointer transition-all duration-500 ease mr-8">
        <span class="i-solar:home-outline" />
      </div>
      <div class="icon-item w-16 h-16 rounded-8 flex items-center justify-center text-8 cursor-pointer transition-all duration-500 ease mr-8">
        <span class="i-emojione-monotone:person-bowing" />
      </div>
      <div class="icon-item w-16 h-16 rounded-8 flex items-center justify-center text-8 cursor-pointer transition-all duration-500 ease">
        <span class="i-uil:setting" />
      </div>
    </div>
  </div>
</template>

<style lang='scss' scoped>
  .custom-wrapper {
    --primary-light: #8abdff;
    --primary: #6d5dfc;
    --primary-dark: #5b0eeb;

    --white: #FFFFFF;
    --greyLight-1: #E4EBF5;
    --greyLight-2: #c8d0e7;
    --greyLight-3: #bec8e4;
    --greyDark: #9baacf;

    $shadow: .3rem .3rem .6rem var(--greyLight-2), -.2rem -.2rem .5rem var(--white);
    $inner-shadow: inset .2rem .2rem .5rem var(--greyLight-2), inset -.2rem -.2rem .5rem var(--white);

    background-color: var(--greyLight-1);

    .container {
      box-shadow:.8rem .8rem 1.4rem var(--greyLight-2), -.2rem -.2rem 1.8rem var(--white);
      .icon-item {
        box-shadow: $shadow;
        color: var(--greyDark);
        &:active {
          box-shadow: $inner-shadow;
          color: var(--primary);
        }
        &:hover {
          color: var(--primary);
        }
      }
    }
  }
</style>

Paused/Resume button

所需知识点如下:

  1. animation-play-state,暂停、运行动画
  2. css选择器
  3. css-filter滤镜
  4. css-选择器

<script lang='ts' setup>

</script>

<template>
  <div class="custom-wrapper p-10">
    <div class="container px-12 py-16 rounded-4 flex items-center justify-center relative">
      <input type="checkbox" class="w-24 h-24 m-2 z-100 absolute opacity-0">
      <span class="circle__btn w-24 h-24 flex items-center justify-center m-2 rounded-12 text-5xl relative cursor-pointer relative z-50">
        <span class="transition-opacity duration-200 linear absolute pause i-carbon:pause-filled" />
        <span class="transition-opacity duration-200 linear absolute play i-carbon:play-filled-alt" />
      </span>
      <span class="circle__back-1 w-24 h-24 rounded-12 blur-1 absolute" />
      <span class="circle__back-2 w-24 h-24 rounded-12 blur-1 absolute" />
    </div>
  </div>
</template>

<style lang='scss' scoped>
  .custom-wrapper {
    --primary-light: #8abdff;
    --primary: #6d5dfc;
    --primary-dark: #5b0eeb;

    --white: #FFFFFF;
    --greyLight-1: #E4EBF5;
    --greyLight-2: #c8d0e7;
    --greyLight-3: #bec8e4;
    --greyDark: #9baacf;

    $shadow: .3rem .3rem .6rem var(--greyLight-2), -.2rem -.2rem .5rem var(--white);
    $inner-shadow: inset .2rem .2rem .5rem var(--greyLight-2), inset -.2rem -.2rem .5rem var(--white);

    background-color: var(--greyLight-1);
    @keyframes waves {
      0% {
        transform: scale(1);
        opacity: 1;
      }

      50% {
        opacity: 1;
      }

      100% {
        transform: scale(2);
        opacity: 0;
      }
    }
    .container {
      box-shadow:.8rem .8rem 1.4rem var(--greyLight-2), -.2rem -.2rem 1.8rem var(--white);
      .circle__btn {
        color: var(--primary);
        background-color: var(--greyLight-1);
        box-shadow:  0.3rem 0.3rem 0.6rem var(--greyLight-2), -0.2rem -0.2rem 0.5rem var(--white);
        .pause {
          opacity: 0;
        }
        .play {
          opacity: 1;
        }
      }
      .circle__back-1 {
        box-shadow: 0.4rem 0.4rem 0.8rem var(--greyLight-2), -0.4rem -0.4rem 0.8rem var(--white);
        background: linear-gradient(to bottom right, var(--greyLight-2) 0%, var(--white) 100%);
        animation: waves 4s linear infinite;
        animation-play-state: paused;
      }
      .circle__back-2 {
        box-shadow: 0.4rem 0.4rem 0.8rem var(--greyLight-2), -0.4rem -0.4rem 0.8rem var(--white);
        animation: waves 4s linear 2s infinite;
        animation-play-state: paused;
      }
      input:checked ~ .circle__btn {
        .pause {
          opacity: 1;
        }
        .play {
          opacity: 0;
        }
      }

      input:checked ~ .circle__back-1, input:checked ~ .circle__back-2 {
        animation-play-state: running;
      }

    }
  }
</style>