Tailwind CSS实现水平线两端十字图标垂直居中布局问题
解决带两端十字图标的水平线布局错位问题
需求描述
需要实现以下布局效果:
- 水平线铺满容器宽度,不超出容器边缘
- 两端的十字SVG图标与水平线垂直居中对齐
- 线条不会超出十字图标向左右延伸
当前问题
尝试多种方法后仍存在布局错位:线条长度不符合预期(过短或过长),图标无法与线条垂直居中对齐。
相关代码
Hero.jsx
import "./text.css"; import stars from "./stars.json"; import { SparklesIcon } from "lucide-react"; import Lottie from "lottie-react"; import Section from "./Section"; import { BottomLine } from "./design/Hero"; function Hero() { return ( <Section className="pt-[12rem] -mt-[5.25rem]" crosses={true} crossesOffset="lg:translate-y-[5.25rem]" customPaddings id="hero" > <div className="relative container max-w-4xl text-center mx-auto mt-20"> <div className="mx-auto inline-flex items-center justify-center font-inter text-white border-[#1e1e1e] bg-[#1e1e1e]/40 border px-4 py-2 rounded-xl"> <SparklesIcon fill="#1e1e1e" className="w-5 h-5 text-[#dee34e] mr-2" /> Our New AI Feature Has Just Returned </div> <h1 className="mt-5 text-5xl lg:text-[80px] font-semibold text-white font-inter"> <span className="bg-gradient-to-r from-blue-500 via-purple-500 to-pink-500 text-transparent bg-clip-text"> Supercharge </span> <br /> your journey </h1> <p className="mt-5 mb-8 text-lg text-[#ebebeb] font-inter max-w-sm mx-auto"> Walk, run, transport better with knowledge of areas with a high and low concentration. </p> <a className="px-6 py-3 text-xl font-semibold text-black bg-white rounded-xl font-inter hover:opacity-90 transition-opacity" href="#" > Use BMap for Free </a> <div className="absolute inset-0 flex justify-center items-center pointer-events-none" aria-hidden="true" > <div className="relative w-[500px] h-[500px] rounded-full bg-gradient-to-r from-purple-500 via-pink-500 to-blue-500 opacity-60 blur-3xl animate-pulse"></div> </div> </div> <BottomLine /> </Section> ); } export default Hero;
Section.jsx
import SectionSvg from "../assets/svg/SectionSvg"; const Section = ({ className, id, crosses, crossesOffset, customPaddings, children, }) => { return ( <div id={id} className={` relative max-w-6xl mx-auto ${customPaddings || `py-10 lg:py-16 xl:py-20 ${crosses ? "lg:py-32 xl:py-40" : ""}`} ${className || ""}`} > {children} <div className="hidden absolute top-0 left-5 w-0.25 h-full bg-stroke-1 pointer-events-none md:block lg:left-7.5 xl:left-10" /> <div className="hidden absolute top-0 right-5 w-0.25 h-full bg-stroke-1 pointer-events-none md:block lg:right-7.5 xl:right-10" /> {crosses && ( <> <div className={`hidden absolute top-0 left-7.5 right-7.5 h-0.25 bg-stroke-1 ${crossesOffset && crossesOffset} pointer-events-none lg:block xl:left-10 right-10`} /> <SectionSvg crossesOffset={crossesOffset} /> </> )} </div> ); }; export default Section;
底部线条相关代码(design/Hero.js)
import { useEffect, useState } from "react"; import { MouseParallax } from "react-just-parallax"; import PlusSvg from "../../assets/svg/PlusSvg"; export const Gradient = () => { return ( <> <div className="relative z-1 h-6 mx-2.5 bg-n-11 shadow-xl rounded-b-[1.25rem] lg:h-6 lg:mx-8" /> <div className="relative z-1 h-6 mx-6 bg-n-11/70 shadow-xl rounded-b-[1.25rem] lg:h-6 lg:mx-20" /> </> ); }; export const BottomLine = () => { return ( <> <div className="hidden absolute top-[55.25rem] left-10 right-10 h-0.25 bg-n-6 pointer-events-none xl:block" /> <PlusSvg className="hidden absolute top-[54.9375rem] left-[2.1875rem] z-2 pointer-events-none xl:block" /> <PlusSvg className="hidden absolute top-[54.9375rem] right-[2.1875rem] z-2 pointer-events-none xl:block" /> </> ); }; const Rings = () => { return ( <> <div className="absolute top-1/2 left-1/2 w-[65.875rem] aspect-square border border-n-2/10 rounded-full -translate-x-1/2 -translate-y-1/2" /> <div className="absolute top-1/2 left-1/2 w-[51.375rem] aspect-square border border-n-2/10 rounded-full -translate-x-1/2 -translate-y-1/2" /> <div className="absolute top-1/2 left-1/2 w-[36.125rem] aspect-square border border-n-2/10 rounded-full -translate-x-1/2 -translate-y-1/2" /> <div className="absolute top-1/2 left-1/2 w-[23.125rem] aspect-square border border-n-2/10 rounded-full -translate-x-1/2 -translate-y-1/2" /> </> ); }; export const BackgroundCircles = ({ parallaxRef }) => { const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); return ( <div className="absolute -top-[42.375rem] left-1/2 w-[78rem] aspect-square border border-n-2/5 rounded-full -translate-x-1/2 md:-top-[38.5rem] xl:-top-[32rem]"> <Rings /> {/* Moving background colored circle balls */} <MouseParallax strength={0.07} parallaxContainerRef={parallaxRef}> <div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom rotate-[46deg]"> <div className={`w-2 h-2 -ml-1 -mt-36 bg-gradient-to-b from-[#DD734F] to-[#1A1A32] rounded-full transition-transform duration-500 ease-out ${mounted ? "translate-y-0 opacity-100" : "translate-y-10 opacity-0"}`} /> </div> <div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom -rotate-[56deg]"> <div className={`w-4 h-4 -ml-1 -mt-32 bg-gradient-to-b from-[#DD734F] to-[#1A1A32] rounded-full transition-transform duration-500 ease-out ${mounted ? "translate-y-0 opacity-100" : "translate-y-10 opacity-0"}`} /> </div> <div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom rotate-[54deg]"> <div className={`hidden w-4 h-4 -ml-1 mt-[12.9rem] bg-gradient-to-b from-[#B9AEDF] to-[#1A1A32] rounded-full xl:block transit transition-transform duration-500 ease-out ${mounted ? "translate-y-0 opacity-100" : "translate-y-10 opacity-0"}`} /> </div> <div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom -rotate-[65deg]"> <div className={`w-3 h-3 -ml-1.5 mt-52 bg-gradient-to-b from-[#B9AEDF] to-[#1A1A32] rounded-full transition-transform duration-500 ease-out ${mounted ? "translate-y-0 opacity-100" : "translate-y-10 opacity-0"}`} /> </div> <div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom -rotate-[85deg]"> <div className={`w-6 h-6 -ml-3 -mt-3 bg-gradient-to-b from-[#88E5BE] to-[#1A1A32] rounded-full transition-transform duration-500 ease-out ${mounted ? "translate-y-0 opacity-100" : "translate-y-10 opacity-0"}`} /> </div> <div className="absolute bottom-1/2 left-1/2 w-0.25 h-1/2 origin-bottom rotate-[70deg]"> <div className={`w-6 h-6 -ml-3 -mt-3 bg-gradient-to-b from-[#88E5BE] to-[#1A1A32] rounded-full transition-transform duration-500 ease-out ${mounted ? "translate-y-0 opacity-100" : "translate-y-10 opacity-0"}`} /> </div> </MouseParallax> </div> ); };
PlusSvg.jsx
const PlusSvg = ({ className = "" }) => { return ( <svg className={`${className} || ""`} width="11" height="11" fill="none"> <path d="M7 1a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h2a1 1 0 0 1 1 1v2a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V8a1 1 0 0 1 1-1h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H8a1 1 0 0 1-1-1V1z" fill="#ada8c4" /> </svg> ); }; export default PlusSvg;
SectionSvg.jsx
import PlusSvg from "./PlusSvg"; const SectionSvg = ({ crossesOffset }) => { return ( <> <PlusSvg className={`hidden absolute -top-[0.3125rem] left-[1.5625rem] ${crossesOffset && crossesOffset} pointer-events-none lg:block xl:left-[2.1875rem]`} /> <PlusSvg className={`hidden absolute -top-[0.3125rem] right-[1.5625rem] ${crossesOffset && crossesOffset} pointer-events-none lg:block xl:right-[2.1875rem]`} /> </> ); }; export default SectionSvg;
解决方案
核心问题分析
当前实现使用绝对定位分别放置线条和图标,通过固定数值调整位置,这种方式无法自适应容器变化,且容易出现对齐偏差。需要改用弹性布局,让线条和图标形成一个整体,确保对齐和长度适配。
修改BottomLine组件
替换原有的绝对定位实现,使用flex布局实现线条和图标的统一对齐:
export const BottomLine = () => { return ( <div className="hidden absolute bottom-0 left-10 right-10 flex items-center pointer-events-none xl:block"> <PlusSvg className="z-2" /> <div className="flex-1 h-0.25 bg-n-6 mx-2" /> <PlusSvg className="z-2" /> </div> ); };
flex items-center确保图标与线条垂直居中flex-1让中间的线条自动填充剩余空间,保证线条长度适配容器且不超出图标- 移除固定
top数值,改为bottom-0(可根据需求调整垂直位置,或通过父容器padding控制)
调整Section组件中的顶部线条实现
同样修改顶部的线条和图标布局,避免固定定位偏差:
{crosses && ( <> <div className={`hidden absolute top-0 left-10 right-10 flex items-center ${crossesOffset} pointer-events-none lg:block`}> <PlusSvg className="z-2" /> <div className="flex-1 h-0.25 bg-stroke-1 mx-2" /> <PlusSvg className="z-2" /> </div> </> )}
同时删除原有的SectionSvg组件调用,因为线条和图标已整合在同一个flex容器中。
优化PlusSvg组件
移除多余逻辑,确保className正常传递:
const PlusSvg = ({ className = "" }) => { return ( <svg className={className} width="11" height="11" fill="none"> <path d="M7 1a1 1 0 0 0-1-1H5a1 1 0 0 0-1 1v2a1 1 0 0 1-1 1H1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h2a1 1 0 0 1 1 1v2a1 1 0 0 0 1 1h1a1 1 0 0 0 1-1V8a1 1 0 0 1 1-1h2a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1H8a1 1 0 0 1-1-1V1z" fill="#ada8c4" /> </svg> ); }; export default PlusSvg;
效果说明
- flex布局让线条和图标作为整体,自动实现垂直居中,线条长度自适应容器且不超出图标范围
- 移除固定像素位置值,避免不同屏幕尺寸下的错位
- 保留原有的响应式控制(
hidden xl:block),确保在指定屏幕尺寸下显示
内容的提问来源于stack exchange,提问作者BenElson445
相关产品推荐
相关产品推荐

