You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为带动态边框的容器实现类灯泡发光光晕效果?

问题描述

我有一个带有动态移动边框的容器,目前该功能运行正常。最后一步需要为其实现类似灯泡的发光光晕效果(效果为跟随动态亮段的柔和扩散黄色光晕)。截至目前,我已尝试设置颜色、模糊及亮度效果,但未达到预期效果,不确定如何叠加多层效果,希望能得到帮助。

以下是我目前的代码:

import React, { useState } from 'react';
import styled, { createGlobalStyle, keyframes } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  *, *::before, *::after {
    box-sizing: border-box;
  }

  body {
    display: grid;
    place-content: center;
    gap: 2rem;
    min-height: 100vh;
    background-image: conic-gradient(
      at 125% 50%,
      #b78cf7,
      #ff7c94,
      #ffcf0d,
      #ff7c94,
      #b78cf7
    );
    font-family: system-ui;
  }
`;

const continuousDashOffsetAnimation = keyframes`
  from {
    stroke-dashoffset: 0;
  }
  to {
    stroke-dashoffset: -50px;
  }
`;

const Box = styled.div`
  cursor: pointer;
  font-size: 2rem;
  font-family: inherit;
  font-weight: 700;
  color: hsl(320, 40%, 40%);
  background-color: hsl(349 100% 95%);
  width: 510px;
  height: 100px;
  border: 0;
  border-radius: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: center;

  --glow-line-color: #FFD600;
  --glow-line-thickness: 2px;
  --glow-line-length: ${props => (props.speed > 15 ? "30px" : "10px")};
  --glow-blur-color: #FFD600;
  --glow-blur-size: 5px;
  --glow-offset: 0px;
  --animation-speed: ${props => (props.speed > 15 ? "500ms" : "1500ms")};
  --container-offset: 100px;
  --intense-glow-size: 15px;
  position: relative;

  .glow-container {
    pointer-events: none;
    position: absolute;
    inset: calc(var(--container-offset) / -2);
    width: calc(100% + var(--container-offset));
    height: calc(100% + var(--container-offset));
    opacity: 1;
  }

  .glow-blur, .glow-line {
    width: calc(100% - var(--container-offset) + var(--glow-offset));
    height: calc(100% - var(--container-offset) + var(--glow-offset));
    x: calc((var(--container-offset) / 2) + calc(var(--glow-offset) / -2));
    y: calc((var(--container-offset) / 2) + calc(var(--glow-offset) / -2));
    fill: transparent;
    stroke: black;
    stroke-width: 5px;
    stroke-dasharray: var(--glow-line-length) calc(50px - var(--glow-line-length));
    animation: ${continuousDashOffsetAnimation} var(--animation-speed) linear infinite;
  }

  .glow-line {
    stroke: var(--glow-line-color);
    stroke-width: var(--glow-line-thickness);
  }

  .glow-blur {
    filter: 
      blur(var(--glow-blur-size)) 
      brightness(5.5); 
    stroke: var(--glow-blur-color);
    stroke-width: var(--glow-blur-size);
  }

  &:after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    border-radius: inherit;
    background: radial-gradient(ellipse at center, rgba(255,214,0,0.6) 0%, transparent 70%);
    filter: blur(var(--intense-glow-size));
    z-index: -1;
  }
`;

const App = () => {
  const [speed, setSpeed] = useState(10); // Initially set to 10 as an example
  
  return (
    <>
      <GlobalStyle />
      <Box speed={speed}>
        Hi there 👋
        <svg className="glow-container">
          <rect rx="1.25rem" pathLength="100" strokeLinecap="round" className="glow-blur"></rect>
          <rect rx="1.25rem" pathLength="100" strokeLinecap="round" className="glow-line"></rect>
        </svg>
        <button onClick={() => setSpeed(prevSpeed => (prevSpeed > 15 ? 10 : 20))}>
          Toggle Speed
        </button>
      </Box>
    </>
  );
}

export default App;
解决方案

要实现类似灯泡的分层发光效果,核心是通过多层SVG描边叠加不同强度的模糊和亮度,同时配合容器背景的径向渐变光晕。以下是修改后的完整代码:

import React, { useState } from 'react';
import styled, { createGlobalStyle, keyframes } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  *, *::before, *::after {
    box-sizing: border-box;
  }

  body {
    display: grid;
    place-content: center;
    gap: 2rem;
    min-height: 100vh;
    background-image: conic-gradient(
      at 125% 50%,
      #b78cf7,
      #ff7c94,
      #ffcf0d,
      #ff7c94,
      #b78cf7
    );
    font-family: system-ui;
  }
`;

const continuousDashOffsetAnimation = keyframes`
  from {
    stroke-dashoffset: 0;
  }
  to {
    stroke-dashoffset: -50px;
  }
`;

const Box = styled.div`
  cursor: pointer;
  font-size: 2rem;
  font-family: inherit;
  font-weight: 700;
  color: hsl(320, 40%, 40%);
  background-color: hsl(349 100% 95%);
  width: 510px;
  height: 100px;
  border: 0;
  border-radius: 1.25rem;
  display: flex;
  align-items: center;
  justify-content: center;

  --glow-line-color: #FFD600;
  --glow-line-thickness: 2px;
  --glow-line-length: ${props => (props.speed > 15 ? "30px" : "10px")};
  --glow-blur-color: #FFD600;
  --glow-blur-size: 8px;
  --glow-intense-blur: 15px;
  --glow-offset: 0px;
  --animation-speed: ${props => (props.speed > 15 ? "500ms" : "1500ms")};
  --container-offset: 100px;
  --intense-glow-size: 20px;
  position: relative;

  .glow-container {
    pointer-events: none;
    position: absolute;
    inset: calc(var(--container-offset) / -2);
    width: calc(100% + var(--container-offset));
    height: calc(100% + var(--container-offset));
    opacity: 1;
  }

  .glow-blur, .glow-line, .glow-intense {
    width: calc(100% - var(--container-offset) + var(--glow-offset));
    height: calc(100% - var(--container-offset) + var(--glow-offset));
    x: calc((var(--container-offset) / 2) + calc(var(--glow-offset) / -2));
    y: calc((var(--container-offset) / 2) + calc(var(--glow-offset) / -2));
    fill: transparent;
    stroke-dasharray: var(--glow-line-length) calc(50px - var(--glow-line-length));
    animation: ${continuousDashOffsetAnimation} var(--animation-speed) linear infinite;
    strokeLinecap: round;
  }

  .glow-line {
    stroke: var(--glow-line-color);
    stroke-width: var(--glow-line-thickness);
    opacity: 0.9;
  }

  .glow-blur {
    filter: blur(var(--glow-blur-size)) brightness(3);
    stroke: var(--glow-blur-color);
    stroke-width: var(--glow-blur-size);
    opacity: 0.7;
  }

  .glow-intense {
    filter: blur(var(--glow-intense-blur)) brightness(4);
    stroke: var(--glow-blur-color);
    stroke-width: var(--glow-intense-blur);
    opacity: 0.5;
  }

  &:after {
    content: '';
    position: absolute;
    top: -5px;
    left: -5px;
    right: -5px;
    bottom: -5px;
    border-radius: inherit;
    background: radial-gradient(ellipse at center, rgba(255,214,0,0.3) 0%, transparent 60%);
    filter: blur(var(--intense-glow-size));
    z-index: -1;
    opacity: 0.6;
  }
`;

const App = () => {
  const [speed, setSpeed] = useState(10);
  
  return (
    <>
      <GlobalStyle />
      <Box speed={speed}>
        Hi there 👋
        <svg className="glow-container">
          <rect rx="1.25rem" className="glow-intense"></rect>
          <rect rx="1.25rem" className="glow-blur"></rect>
          <rect rx="1.25rem" className="glow-line"></rect>
        </svg>
        <button onClick={() => setSpeed(prevSpeed => (prevSpeed > 15 ? 10 : 20))}>
          Toggle Speed
        </button>
      </Box>
    </>
  );
}

export default App;
关键改动说明
  • 新增--glow-intense-blur变量,专门控制强光晕的模糊半径,实现灯泡发光的层次感
  • 在SVG中添加第三层rect(.glow-intense),作为最外层的强发光效果,通过更大的模糊和更高的亮度模拟光晕扩散感
  • 调整.glow-blur的参数,降低亮度并增大模糊,让基础光晕更柔和,避免和强光晕冲突
  • 修改:after伪元素的径向渐变范围和透明度,扩大伪元素尺寸让光晕更自然,同时降低整体透明度避免刺眼
  • 调整各层描边的透明度,通过多层叠加实现渐变式发光,更接近灯泡发光的真实质感

内容的提问来源于stack exchange,提问作者Angel Hadzhiev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 17:05:57