diff --git a/components/affix/index.tsx b/components/affix/index.tsx
index 8f4b37710..95155dd39 100644
--- a/components/affix/index.tsx
+++ b/components/affix/index.tsx
@@ -27,10 +27,11 @@ import useStyle from './style';
 function getDefaultTarget() {
   return typeof window !== 'undefined' ? window : null;
 }
-enum AffixStatus {
-  None,
-  Prepare,
-}
+const AFFIX_STATUS_NONE = 0;
+const AFFIX_STATUS_PREPARE = 1;
+
+type AffixStatus = typeof AFFIX_STATUS_NONE | typeof AFFIX_STATUS_PREPARE;
+
 export interface AffixState {
   affixStyle?: CSSProperties;
   placeholderStyle?: CSSProperties;
@@ -82,7 +83,7 @@ const Affix = defineComponent({
     const state = reactive({
       affixStyle: undefined,
       placeholderStyle: undefined,
-      status: AffixStatus.None,
+      status: AFFIX_STATUS_NONE,
       lastAffix: false,
       prevTarget: null,
       timeout: null,
@@ -98,7 +99,12 @@ const Affix = defineComponent({
     const measure = () => {
       const { status, lastAffix } = state;
       const { target } = props;
-      if (status !== AffixStatus.Prepare || !fixedNode.value || !placeholderNode.value || !target) {
+      if (
+        status !== AFFIX_STATUS_PREPARE ||
+        !fixedNode.value ||
+        !placeholderNode.value ||
+        !target
+      ) {
         return;
       }
 
@@ -108,7 +114,7 @@ const Affix = defineComponent({
       }
 
       const newState = {
-        status: AffixStatus.None,
+        status: AFFIX_STATUS_NONE,
       } as AffixState;
       const placeholderRect = getTargetRect(placeholderNode.value as HTMLElement);
 
@@ -172,7 +178,7 @@ const Affix = defineComponent({
     };
     const prepareMeasure = () => {
       Object.assign(state, {
-        status: AffixStatus.Prepare,
+        status: AFFIX_STATUS_PREPARE,
         affixStyle: undefined,
         placeholderStyle: undefined,
       });
@@ -253,12 +259,13 @@ const Affix = defineComponent({
     });
 
     const { prefixCls } = useConfigInject('affix', props);
-    const [wrapSSR, hashId] = useStyle(prefixCls);
+    const [wrapSSR, hashId, cssVarCls] = useStyle(prefixCls);
     return () => {
       const { affixStyle, placeholderStyle, status } = state;
       const className = classNames({
         [prefixCls.value]: affixStyle,
         [hashId.value]: true,
+        [cssVarCls.value]: true,
       });
       const restProps = omit(props, [
         'prefixCls',
diff --git a/components/affix/style/index.ts b/components/affix/style/index.ts
index f97731ae5..be895766d 100644
--- a/components/affix/style/index.ts
+++ b/components/affix/style/index.ts
@@ -1,17 +1,21 @@
 import type { CSSObject } from '../../_util/cssinjs';
-import type { FullToken, GenerateStyle } from '../../theme/internal';
-import { genComponentStyleHook, mergeToken } from '../../theme/internal';
+import { FullToken, GenerateStyle, genStyleHooks, GetDefaultToken } from '../../theme/internal';
 
-export interface ComponentToken {}
+export interface ComponentToken {
+  /**
+   * @desc 弹出层的 z-index
+   * @descEN z-index of popup
+   */
+  zIndexPopup: number;
+}
 
 interface AffixToken extends FullToken<'Affix'> {
-  zIndexPopup: number;
+  //
 }
 
 // ============================== Shared ==============================
 const genSharedAffixStyle: GenerateStyle<AffixToken> = (token): CSSObject => {
   const { componentCls } = token;
-
   return {
     [componentCls]: {
       position: 'fixed',
@@ -20,10 +24,9 @@ const genSharedAffixStyle: GenerateStyle<AffixToken> = (token): CSSObject => {
   };
 };
 
-// ============================== Export ==============================
-export default genComponentStyleHook('Affix', token => {
-  const affixToken = mergeToken<AffixToken>(token, {
-    zIndexPopup: token.zIndexBase + 10,
-  });
-  return [genSharedAffixStyle(affixToken)];
+export const prepareComponentToken: GetDefaultToken<'Affix'> = token => ({
+  zIndexPopup: token.zIndexBase + 10,
 });
+
+// ============================== Export ==============================
+export default genStyleHooks('Affix', genSharedAffixStyle, prepareComponentToken);
diff --git a/components/affix/utils.ts b/components/affix/utils.ts
index 62ce50f27..08b46ea1e 100644
--- a/components/affix/utils.ts
+++ b/components/affix/utils.ts
@@ -9,8 +9,11 @@ export function getTargetRect(target: BindElement): DOMRect {
     : ({ top: 0, bottom: window.innerHeight } as DOMRect);
 }
 
-export function getFixedTop(placeholderRect: DOMRect, targetRect: DOMRect, offsetTop: number) {
-  if (offsetTop !== undefined && targetRect.top > placeholderRect.top - offsetTop) {
+export function getFixedTop(placeholderRect: DOMRect, targetRect: DOMRect, offsetTop?: number) {
+  if (
+    offsetTop !== undefined &&
+    Math.round(targetRect.top) > Math.round(placeholderRect.top) - offsetTop
+  ) {
     return `${offsetTop + targetRect.top}px`;
   }
   return undefined;
@@ -19,9 +22,12 @@ export function getFixedTop(placeholderRect: DOMRect, targetRect: DOMRect, offse
 export function getFixedBottom(
   placeholderRect: DOMRect,
   targetRect: DOMRect,
-  offsetBottom: number,
+  offsetBottom?: number,
 ) {
-  if (offsetBottom !== undefined && targetRect.bottom < placeholderRect.bottom + offsetBottom) {
+  if (
+    offsetBottom !== undefined &&
+    Math.round(targetRect.bottom) < Math.round(placeholderRect.bottom) + offsetBottom
+  ) {
     const targetBottomOffset = window.innerHeight - targetRect.bottom;
     return `${offsetBottom + targetBottomOffset}px`;
   }
@@ -29,7 +35,7 @@ export function getFixedBottom(
 }
 
 // ======================== Observer ========================
-const TRIGGER_EVENTS = [
+const TRIGGER_EVENTS: (keyof WindowEventMap)[] = [
   'resize',
   'scroll',
   'touchstart',