<div class="wrapper">
<header>
<h1>Circular Wipe</h1>
<p>Hover, tap, or focus below to see transition</p>
</header>
<div class="scenes" tabindex="0">
<div class="scene-1 scene"></div>
<svg class="scene-2 scene" viewBox="0 0 1920 820">
<defs>
<radialGradient id="myGradient">
<stop offset="70%" stop-color="white" />
<stop offset="100%" stop-color="transparent" />
</radialGradient>
<mask id="imageMask">
<circle id="circleMask" cx="50%" cy="50%" r="50%" fill="url('#myGradient')" />
</mask>
</defs>
<image width="100%" height="100%" preserveAspectRatio="xMidYMid slice" href="img/scene-2.jpg" mask="url(#imageMask)"></image>
</svg>
</div>
<div class="visualizer">
<div class="visualizer-mask"></div>
</div>
<p>This is the SVG mask version.</p>
</div>
@font-face {
font-family: "Star Jedi Hollow";
src: url("fonts/Starjedi-hollow.woff2");
}
:root {
--ratio: 1920 / 820;
}
.scenes {
position: relative;
aspect-ratio: var(--ratio);
border: 2px solid #ccc;
width: 100%;
}
.scene {
position: absolute;
inset: 0;
}
.scene-1 {
background-size: cover;
background-image: url("img/scene-1.jpg");
}
.scene-2 {
width: 100%;
height: auto;
}
.scenes:is(:hover, :focus) #circleMask {
animation: scene-transition 2s linear forwards;
}
#circleMask {
transform: scale(0);
transform-origin: center;
}
@keyframes scene-transition {
to {
transform: scale(4);
}
}
/* everything else */
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
display: grid;
place-items: center;
min-height: 100vh;
margin: 0;
padding: 20px;
color: #fff;
background-color: #111;
font-size: clamp(0.75rem, 0.3rem + 1.9vw, 1.5rem);
font-family: "Roboto", sans-serif;
}
.wrapper {
display: grid;
gap: 1.5rem;
width: min(1000px, 100%);
justify-items: center;
}
.wrapper header {
text-align: center;
margin: 0;
}
h1 {
font-family: "Star Jedi Hollow", serif;
font-size: clamp(1.5rem, 1.25rem + 1.9vw, 3rem);
color: rgb(255, 255, 44);
margin: 0;
}
.visualizer {
display: flex;
justify-content: center;
width: min(150px, 25vw);
aspect-ratio: 2.4 / 1;
outline: 2px solid #ccc;
background-color: #333;
background-image: linear-gradient(
45deg,
#444 25%,
transparent 25%,
transparent 75%,
#444 75%
),
linear-gradient(45deg, #444 25%, transparent 25%, transparent 75%, #444 75%);
background-size: 16px 16px, 16px 16px;
background-position: 0 0, 8px 8px;
overflow: hidden;
}
.visualizer-mask {
background-image: radial-gradient(
circle at center,
white 70%,
transparent 100%
);
height: 100%;
aspect-ratio: 1/1;
margin: 0 auto;
border-radius: 50%;
transform: scale(0);
transform-origin: center;
}
.scenes:is(:hover, :focus) + .visualizer .visualizer-mask {
animation: scene-transition 2s linear forwards;
}
A circular wipe transition between scenes, just like in Star Wars. I wanted to explore how to execute the effect with the best cross-browser support. This version uses a SVG Mask. This does not work in Chrome!
You can read my article where I discuss this implementation and compare it with other methods such as animating a CSS mask using @property
, or animating a SVG mask.