背景:
需要绝对定位某一个元素,但是元素的right值需要根据另一个元素的宽度动态变化;
方案
- 获取到某一个元素的固定宽度
- 将变量传到less文件中
实现
a. 获取元素的宽度
const headerRightRef = useRef<HTMLDivElement>(null);
const setHeaderRightWidth = useUaiHeaderLayout((s) => s.setHeaderRightWidth);
useEffect(() => {
const el = headerRightRef.current;
if (!el) return;
const update = () => {
setHeaderRightWidth(Math.round(el.getBoundingClientRect().width));
};
update();
if (typeof ResizeObserver !== 'undefined') {
const ro = new ResizeObserver(() => update());
ro.observe(el);
return () => ro.disconnect();
}
window.addEventListener('resize', update);
return () => window.removeEventListener('resize', update);
}, [setHeaderRightWidth]);
return (<div><div ref={headerRightRef} className={styles['header-right-wrapper']}>....</div></div>)
import { create } from 'zustand';
type HeaderLayoutState = {
headerRightWidth: number;
setHeaderRightWidth: (width: number) => void;
};
const useUaiHeaderLayout = create<HeaderLayoutState>((set) => ({
headerRightWidth: 0,
setHeaderRightWidth: (width) => set({ headerRightWidth: width }),
}));
export default useUaiHeaderLayout;
2.将宽度定义成变量传到样式文件.less文件中
const headerRightWidth = useUaiHeaderLayout((s) => s.headerRightWidth);
...
return
(
<div
className={
mainAppHeaderRightWidthNumber != null
? `${styles['communication-notification']} ${styles['communication-notification--main-right']}`
: styles['communication-notification']
}
style={
mainAppHeaderRightWidthNumber != null
? ({
['--main-app-header-right-width' as unknown as keyof CSSProperties]: `${headerRightWidth}px`,
} as CSSProperties)
: undefined
}
>
...
</div>)
.communication-notification--main-right {
right: var(--main-app-header-right-width, 415px);
}
原理
上面的可以改成下面的写法:
<div
style={
mainAppHeaderRightWidthNumber != null
? ({
'--main-app-header-right-width': `${headerRightWidth}px`,
} as CSSProperties)
: undefined
}
>
</div>)
- 核心是css自定义属性(css 自变量),你在React中把一个"变量"写到元素的
style上,然后在.less里有var(--xxx)读出来,用来控制right。 - 上面代码做了两件事 *1. 在这个组件根节点上“声明一个 CSS 变量”
style={{
['--main-app-header-right-width' as ...]: '123px'
}}
等价于在 HTML 上这样写:
<div style="--main-app-header-right-width: 123px;"></div>
- 在 CSS 里“读取这个变量”并用它参与布局
.communication-notification--main-right {
right: var(--main-app-header-right-width, 415px);
}
含义是:right 优先用 --main-app-header-right-width 的值;如果没定义,就用默认 415px(这是 var() 的 fallback)。
常见使用方法
1) 动态主题色(按钮/高亮)
<div style={{'--primary':'#1677ff'} as React.Cssproperties} className={styles.box}>
.box{
border-color: var(--primary);
color:var(--primary)
}
2) 动态尺寸:侧边栏宽度影响内容区
<div style={{ '--sidebar-w': '280px' } as React.CSSProperties} className={styles.layout} />
.layout {
padding-left: var(--sidebar-w);
}ar(--primary)
}
3) 动态做“计算”:用 calc() 拼装
<div style={{ '--w': '360px' } as React.CSSProperties} className={styles.pop} />
.pop {
right: calc(var(--w) + 12px); // 在 CSS 里加偏移
}
4) 动画时长/延迟由业务控制
<div style={{ '--dur': '200ms' } as React.CSSProperties} className={styles.anim} />
.anim {
transition: opacity var(--dur) ease;
}
5) 同一个变量控制多个子元素(继承作用域)
<div style={{ '--gap': '8px' } as React.CSSProperties} className={styles.list}>
...
</div>
.list { gap: var(--gap); }
.list :global(.ant-btn) { margin-left: var(--gap); }
只要在父元素上定义 --x,子元素都能用(CSS 变量会沿 DOM 向下“继承”):