Porting vanilla CSS bubble to Tailwind


I started exploring Tailwind CSS and decided to port one of my favorite CSS codepen in it. I wanted to see what the learning curve looks like and how tailwind actually helps in code management and future maintenance.

The Code repo and stackblitz links:

The component I picked is an animated CSS sphere that looks like a bubble. The whole process with progression is explained in this post https://cssanimation.rocks/spheres/

The codepen for the version that I’m panning to port.

https://codepen.io/donovanh/pen/nRgZjd

{{< renderhtml `

See the Pen Spheres tutorial: 6 Bubble (animated) by Donovan Hutchinson (@donovanh) on CodePen.

`>}}

The CSS in this codepen is pretty clean and but the individual attributes of the component definition are not sharable. Like background color gradients, transforms etc. Tailwind being a utility library makes this process seamless. I was able to replicate most of it using base utility classes and the rest I extended using external plugins and custom components. The final CSS file looks pretty clean and uses building block utility classes to achieve the final result.

.stage {
  @apply m-auto w-[200px] h-[200px]
}

.ball {
  @apply block relative rounded-full w-full
  h-full bg-radial-circle-b-blue-shades-with-stops
  before:content-[''] before:absolute before:w-[90%]
  before:h-[90%] before:rounded-full
  before:top-1 before:left-2
  before:bg-radial-circle-none-custom-one-white-with-stops
  before:z-10 before:blur-md
  after:content-[''] after:absolute after:hidden
  after:top-2 after:left-5
  after:w-[80%] after:h-[80%] after:rounded-full
  after:z-10 after:blur-sm after:rotate-45
}

.bubble {
  @apply animate-bubble-anim
  bg-radial-circle-none-custom-two-bubble-with-stops
  before:blur-xl before:h-[80%] before:w-[40%]
  before:translate-x-[131%]
  before:translate-y-[58%]
  before:rotate-12
  before:bg-radial-circle-none-bubble-before-with-stops
  after:block after:bg-radial-circle-none-custom-three-bubble-after-with-stops
}

Behind the scene I’m using https://github.com/benface/tailwindcss-gradients for radial gradient and the extended tailwind looks like this.

module.exports = {
  content: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
  theme: {
    radialGradientShapes: {
      // defaults to this value
      default: "ellipse",
      circle: "circle",
    },
    radialGradientSizes: {
      // defaults to this value
      default: "closest-side",
      none: "",
    },
    radialGradientPositions: {
      // defaults to these values
      default: "center",
      t: "top",
      tr: "top right",
      r: "right",
      br: "bottom right",
      b: "bottom",
      bl: "bottom left",
      l: "left",
      tl: "top left",
      "custom-one": "50% 0px",
      "custom-two": "50% 55%",
      "custom-three": "50% 80%",
      "custom-four": "130% 130%",
    },
    radialGradientColors: {
      // defaults to {}
      red: "#f00",
      "black-white-with-stops": ["#000", "#000 45%", "#fff 55%", "#fff"],
      "blue-shades-with-stops": [
        "#81e8f6",
        "#76deef 10%",
        "#055194 80%",
        "#062745 100%",
      ],
      "white-with-stops": ["#ffffff", "rgba(255, 255, 255, 0) 58%"],
      "bubble-with-stops": [
        "rgba(240, 245, 255, 0.9)",
        "rgba(240, 245, 255, 0.9) 40%",
        "rgba(225, 238, 255, 0.8) 60%",
        "rgba(43, 130, 255, 0.4)",
      ],
      "bubble-after-with-stops": [
        "rgba(255, 255, 255, 0)",
        "rgba(255, 255, 255, 0) 74%",
        "white 80%, white 84%",
        "rgba(255, 255, 255, 0) 100%",
      ],
      "bubble-before-with-stops": [
        "rgba(255, 255, 255, 0) 0",
        "rgba(255, 255, 255, 0) 46%",
        "rgba(255, 255, 255, 0.8) 50%",
        "rgba(255, 255, 255, 0.8) 58%",
        "rgba(255, 255, 255, 0) 60%",
        "rgba(255, 255, 255, 0) 100%",
      ],
    },
    extend: {
      animation: {
        "bubble-anim": "bubble-keyframes 2s ease-out infinite",
      },
      keyframes: {
        "bubble-keyframes": {
          "0%": { transform: "scale(1)" },
          "20%": { transform: "scaleY(0.95) scaleX(1.05)" },
          "48%": { transform: "scaleY(1.1) scaleX(0.9)" },
          "68%": { transform: "scaleY(0.98) scaleX(1.02)" },
          "80%": { transform: "scaleY(1.02) scaleX(0.98)" },
          "97%, 100%": { transform: "scale(1)" },
        },
      },
    },
  },
  plugins: [require("tailwindcss-gradients")],
};

The complexity is hidden in the tailwind config file but, IMO, it is much more manageable than vanilla CSS. Tailwind documentation and plugin ecosystem was a huge help in this port.