AI CSS Animations

Watering Can Loader

A watering can tips forward, pours a stream of drops onto a sprout that perks up, then rights itself. Good for growth, onboarding and 'setting things up' moments.

Also known as: watering plant animation, garden loader css, growing plant loader.

HTML

<div class="ldr-watering-can" role="status" aria-label="Loading">
  <svg viewBox="0 0 52 40" aria-hidden="true">
    <ellipse class="ldr-watering-can-soil" cx="42" cy="38.6" rx="7" ry="1.6"/>
    <circle class="ldr-watering-can-drop" cx="39.6" cy="20.5" r="1.6"/>
    <circle class="ldr-watering-can-drop" cx="40.6" cy="20.5" r="1.4"/>
    <circle class="ldr-watering-can-drop" cx="38.6" cy="20.5" r="1.4"/>
    <g class="ldr-watering-can-sprout">
      <path class="ldr-watering-can-stem" d="M42 38.5V30"/>
      <path d="M42 33c-5 0-7-2.5-7-5.5 5 0 7 2.5 7 5.5zM42 31.5c4.5 0 6.5-2.2 6.5-5-4.5 0-6.5 2.2-6.5 5z"/>
    </g>
    <g class="ldr-watering-can-can">
      <path class="ldr-watering-can-line" d="M9 9c0-9 14-9 14 0M25 23l13-13M36.5 8.5l3 3"/>
      <rect x="5" y="8" width="21" height="19" rx="3.5"/>
    </g>
  </svg>
</div>

CSS

.ldr-watering-can {
  --s: var(--ldr-size, 48px);
  --c: var(--ldr-color, #3b82f6);
  width: calc(var(--s) * 1.3);
  height: var(--s);
}
.ldr-watering-can svg {
  display: block;
  width: 100%;
  height: 100%;
  fill: var(--c);
}
.ldr-watering-can-line {
  fill: none;
  stroke: var(--c);
  stroke-width: 3.4;
  stroke-linecap: round;
}
.ldr-watering-can-can {
  transform-origin: 29.8% 43.75%;
  animation: ldr-watering-can-tip 2.8s infinite;
}
.ldr-watering-can-drop {
  fill: color-mix(in srgb, var(--ldr-color, #3b82f6) 80%, transparent);
  opacity: 0;
  animation: ldr-watering-can-drop 2.8s infinite;
}
.ldr-watering-can-drop:nth-child(2) { animation-delay: 0.14s; }
.ldr-watering-can-drop:nth-child(3) { animation-delay: 0.28s; }
.ldr-watering-can-sprout {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: ldr-watering-can-grow 2.8s infinite;
}
.ldr-watering-can-soil {
  fill: color-mix(in srgb, var(--ldr-color, #3b82f6) 30%, transparent);
}
.ldr-watering-can-stem {
  fill: none;
  stroke: var(--c);
  stroke-width: 2;
  stroke-linecap: round;
}
@keyframes ldr-watering-can-tip {
  0%, 16%   { transform: rotate(0); animation-timing-function: cubic-bezier(0.4, 0, 0.3, 1.4); }
  30%, 64%  { transform: rotate(22deg); animation-timing-function: cubic-bezier(0.5, 0, 0.3, 1); }
  80%, 100% { transform: rotate(0); }
}
@keyframes ldr-watering-can-drop {
  0%, 30% { transform: translateY(0); opacity: 0; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.5); }
  31%     { transform: translateY(0); opacity: 1; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.5); }
  43%     { transform: translateY(16%); opacity: 1; }
  45%     { transform: translateY(16%); opacity: 0; }
  46%     { transform: translateY(0); opacity: 0; }
  47%     { transform: translateY(0); opacity: 1; animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.5); }
  59%     { transform: translateY(16%); opacity: 1; }
  61%, 100% { transform: translateY(16%); opacity: 0; }
}
@keyframes ldr-watering-can-grow {
  0%, 40%   { transform: scale(0.8); }
  52%       { transform: scale(1.1); }
  60%, 84%  { transform: scale(1); }
  100%      { transform: scale(0.8); }
}

@media (prefers-reduced-motion: reduce) {
  .ldr-watering-can, .ldr-watering-can *, .ldr-watering-can::before, .ldr-watering-can::after, .ldr-watering-can *::before, .ldr-watering-can *::after {
    animation-duration: 3s;
  }
}

Customizing this loader

  • Color: set --ldr-color on the element or a parent. Currently previewing #3b82f6.
  • Size: set --ldr-size. Every dimension in the snippet is derived from it. Currently previewing 64px.
  • Speed: change the duration on the animation shorthand. Delays on the children are relative, so they keep their rhythm.
  • Accessibility: the root carries role="status" and an aria-label so screen readers announce the wait. The reduced-motion rule at the end slows the animation for users who asked for less motion.

Similar loaders