Frontend Development 19 min read

Recreating the “声生不息” Logo Using Pure CSS with Gradient, Clip‑Path, and Variable‑Based Color Switching

This article demonstrates how to recreate the “声生不息” program logo using only native CSS and a small amount of JavaScript, covering gradient stripes, clip‑path shaping, background‑clip text effects, CSS variables for color toggling, and detailed code snippets for each implementation step.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Recreating the “声生不息” Logo Using Pure CSS with Gradient, Clip‑Path, and Variable‑Based Color Switching

Background

The TV show "声生不息" is a music competition produced by Mango TV, Hong Kong TVB, and Hunan TV. Its logo uses a classic red‑blue color scheme with an infinity symbol, giving a strong sense of design.

This tutorial reproduces the logo using only native CSS , demonstrating many techniques such as repeating-linear-gradient , clip-path , background-clip , Window.getComputedStyle() , and CSSStyleDeclaration.getPropertyValue() .

Result

First, see the effect of the implementation.

Click the semi‑circular shape at the top‑right corner to switch the page theme to white.

Online preview:

👁‍🗨 Github: https://dragonir.github.io/shengshengbuxi/ 👁‍🗨 Codepen: https://codepen.io/dragonir/full/OJQRBad

Implementation

Before starting, define the main colors used in the logo as CSS variables, which will be reused for color switching.

:root {
  --black: #010101;
  --red: #F66034;
  --blue: #0A68DF;
}

Step 0: First Circle 🔴

The first circle is a pure red stripe created with repeating-linear-gradient and a pseudo‑element ::after for the black ring.

<div class="logo">
  <div class="cycle cycle_1"></div>
</div>
.cycle {
  height: 500px;
  width: 500px;
  border-radius: 50%;
  position: relative;
  box-sizing: border-box;
}
.cycle_1 {
  z-index: 2;
  background: var(--red);
  background: repeating-linear-gradient(180deg, var(--red), var(--red) 12px, var(--black) 0, var(--black) 22px);
  border: 12px solid var(--black);
}
.cycle_1::after {
  content: '';
  display: inline-block;
  height: 200px;
  width: 200px;
  background: var(--black);
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -100px;
  margin-left: -100px;
  border-radius: 50%;
  z-index: 3;
}

💡 repeating-linear-gradient

repeating-linear-gradient creates an image composed of repeated linear gradients. It works like linear-gradient but repeats the pattern to fill the entire container.

Syntax:

repeating-linear-gradient([ <angle> | to <side-or-corner> ,]? <color-stop> [, <color-stop>]+ )

<side-or-corner> defines the start point of the gradient line (e.g., to top , to right ).

<angle> specifies the direction in degrees, increasing clockwise.

<color-stop> is a color value optionally followed by a position.

Examples:

// 45° repeating linear gradient from blue to red
repeating-linear-gradient(45deg, blue, red);
// Vertical repeating gradient: blue → green at 40% → red
repeating-linear-gradient(0deg, blue, green 40%, red);
Each repetition’s color‑stop offset is a multiple of the base gradient length, so the final stop should match the first to avoid abrupt changes.

Step 1: Second Circle 🔵

Add a second circle beneath the first, using a left‑to‑right linear gradient.

<div class="logo">
  <div class="cycle cycle_1"></div>
  <div class="cycle cycle_2"></div>
</div>
.cycle_2 {
  margin-left: -160px;
  background: linear-gradient(to right, var(--red), var(--blue));
  border: 12px solid var(--black);
}
.cycle_2::after {
  content: '';
  display: inline-block;
  height: 200px;
  width: 200px;
  background: var(--black);
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -100px;
  margin-left: -100px;
  border-radius: 50%;
  z-index: 3;
}

Step 2: Overlapping Area 🔴🔵

Use clip-path to cut a semi‑circle from the second circle and place it on top.

.cycle_2::before {
  position: absolute;
  box-sizing: border-box;
  top: -12px;
  left: -12px;
  content: '';
  display: inline-block;
  height: 500px;
  width: 500px;
  background: var(--red);
  border-radius: 50%;
  -webkit-clip-path: polygon(0 50%, 100% 50%, 100% 100%, 0 100%);
  clip-path: polygon(0 50%, 100% 50%, 100% 100%, 0 100%);
  z-index: 3;
  border: 12px solid var(--black);
}

💡 clip-path

clip-path defines a visible region for an element; everything outside is hidden.

Syntax:

clip-path: none;
clip-path: url(resources.svg#c1);
clip-path: margin-box;
clip-path: inset(100px 50px);
clip-path: circle(50px at 0 100px);
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);

inset() defines a rectangular clipping area.

circle() defines a circular clipping area.

ellipse() defines an elliptical clipping area.

polygon() defines a polygonal clipping area.

path() defines an arbitrary SVG path.

Step 3: Overlap Optimization 🔴🔵

Set the overlapping part to the same gradient as the second circle, creating the illusion of a smooth transition.

.cycle_2::before {
  background: linear-gradient(to right, var(--red), var(--blue));
}

Step 4: Text 🅰

The logo text uses a left‑to‑right gradient and background-clip: text to show the gradient inside the letters.

<h1 class="text">声生不息</h1>
.text {
  background: linear-gradient(to right, var(--blue), var(--red));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  font-style: italic;
}

💡 background-clip

background-clip controls how far a background extends (border‑box, padding‑box, content‑box, or text).

Syntax:

background-clip: border-box;
background-clip: padding-box;
background-clip: content-box;
background-clip: text;

Step 5: Click‑to‑Toggle Effect 🔲

Click the semi‑circular toggle element to switch the logo from colorful to pure white by changing the CSS variable values defined in :root .

<span class="toggle" id="toggle" title="点击切换颜色"></span>

The toggle’s background includes a noise image for a TV‑static effect.

.toggle {
  background: linear-gradient(to left bottom, var(--blue), rgba(0,0,0,0)), url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAgMAAADXB5lNAAAADFBMVEUvLy9eXl6AgICoqKhWH7o7AAAABHRSTlMSEhIS3WyPCwAAA1hJREFUOMsN0M3rDHEcwPH3d3y/4zcr67s1s3bIU62y8nBxcVCf79pZ4WBWsx6TVbvyEKUolJrxmBTj4SecVqE4OTjgIP6D5eC8DkouOJAj19fxhXJCWn811mk1Sp1q0J0q6AoNF7ZQ0uD+74CBj3otoUUEmJc0wqVEr2Ulatp1/6HYA9SGwfn+s6ftD8zsbic1idsPVrfcoQRYSrvbd7PdA7TY6cKcbfrwRXaJaqgTXSfDKd625S7XGB1YraJ0yuatOJmJvf5aqIwYINvBGIr+gZiDl80Qdoh3M1GTfuCzf1+yEetme3loJ3Hf6yijG5S9rRa7XI7Nzu1AYGF5Bd1cNeplTmN8yJpV8kYrpKEIAzXDgbBK2QhhTb37NP4P1aqRZ3ua6DVLb2AKjVpgBkbHie4QGFVqxDcpgL4tlTUMNKKgazpmWC+CkBBkTu59dpl+XikMg+U5izd/9z+KpxcFYvxxs01Vtho32XLZBNRmy8YWQBszOV6ES9r7cvQdshRbKVdfOrDKeyB+MeXsWvMmI95/Pdsp7J5MydZHR9MonithyhIllnSppjGaQRkb7vVyTaqNhLUsVI5I/HEDi3JYWdu+KEgsmkzJXGPZ97wQyqPREfp+vmAvzo3AfhF9HvZS1SiZL9H4pVgfhmofCltJ3wxq9/961Aaqq3HpzsFroqtPe9SVm3Ol5yd3f99TueB46l+9lB/drm4PxXs/4j4j5k6pAzS88njnDp72JijRYlYFRMaxfY8q20pWZjGLdKsCP2YoVYXl9RK1Kp7Xpx8MLYEe+gIWlUDwJNABR0AVAGQ4rfcCrci5YQYZonhi9ckLVrkTeCTeL5+0H7+Lw1baYjGu+6ddepc6qeLc8EhvL3dvf5Xi9maHyrGnCmFXXo7bk83O3C6FFYVDURtfLD4YVUpO011EfYvktpukxpKogevhPViJPC6tmWnOcxkaJYnwOw2zyoYKeAmKIlfpILLxBmOo3yLlkzh5+yTKmkvtrsc3oP8Tx7t8YTms2Be9a0TJNJ21Gb6k5mwY9Vn/P2vRSHu7tiZ2kx6mrMtCoqPG+9w3YWxOw5EZDcszz+tUQhZlq8j8Rw77ynqzi7XaV3kH8x62ScfWdhZpkgX3wWdZcibtbFASgOEfZmfZzbdc/O0AAAAASUVORK5CYII=') repeat 0 0;
  background-repeat: repeat;
  animation: bg-animation .2s infinite;
}
@keyframes bg-animation {
  0% { transform: translate(0,0); }
  10% { transform: translate(-5%,-5%); }
  /* ... */
  100% { transform: translate(5%,0); }
}

JavaScript toggles the CSS variables:

const root = document.querySelector(':root');
const getCssVariable = (key) => getComputedStyle(root).getPropertyValue(key);
const setCssVariable = (key, value) => { root.style.setProperty(key, value); };

document.getElementById('toggle').addEventListener('click', () => {
  if (getCssVariable('--blue') === '#FFFFFF') {
    setCssVariable('--blue', '#0A68DF');
    setCssVariable('--red', '#F66036');
  } else {
    setCssVariable('--blue', '#FFFFFF');
    setCssVariable('--red', '#FFFFFF');
  }
}, false);

💡 Window.getComputedStyle()

Window.getComputedStyle() returns a CSSStyleDeclaration object containing the computed values of all CSS properties for an element.

let style = window.getComputedStyle(element, [pseudoElt]);

💡 CSSStyleDeclaration.getPropertyValue()

Retrieves the value of a specific CSS property from a CSSStyleDeclaration object.

var value = style.getPropertyValue(property);

Summary

The article covered the following key points:

repeating-linear-gradient for striped backgrounds

clip-path for shape clipping

background-clip for extending backgrounds to text

Window.getComputedStyle() for obtaining computed CSS values

CSSStyleDeclaration.getPropertyValue() for reading specific property values

For more front‑end knowledge or Web 3D development topics, check my previous articles. Please credit the original source and author if you repost, and don’t forget to give a “three‑click” like 👍.

Appendix

[1] 📷 Front‑end implementation of a cool browser‑side QR code scanner

[2] 🌏 Front‑end tile map loading – Zelda: Breath of the Wild

[3] 🆒 CSS‑only cyber‑punk 2077 visual effect

3D References

[1] 🦊 Three.js – 3D open‑world mini‑game: Ali’s Multiverse

[2] 🔥 Three.js – Elden Ring dynamic logo flame effect

[3] 🐼 Three.js – 2022 Winter Olympics themed 3D page with Bing Dwen‑Dwen

References

https://developer.mozilla.org/zh-CN/docs/Web/CSS/gradient/repeating-linear-gradient

https://developer.mozilla.org/zh-CN/docs/Web/CSS/clip-path

https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-clip

https://developer.mozilla.org/zh-CN/docs/Web/API/Window/getComputedStyle

https://developer.mozilla.org/zh-CN/docs/Web/API/CSSStyleDeclaration/getPropertyValue

frontendJavaScriptWeb DevelopmentCSSgradientclip-pathBackground-Clip
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.