diff --git a/components/_util/hooks/useSize.ts b/components/_util/hooks/useSize.ts
new file mode 100644
index 000000000..4e70469eb
--- /dev/null
+++ b/components/_util/hooks/useSize.ts
@@ -0,0 +1,26 @@
+import { computed, ComputedRef, inject, provide, UnwrapRef } from 'vue';
+import { ConfigProviderProps, defaultConfigProvider, SizeType } from '../../config-provider';
+
+const sizeProvider = Symbol('SizeProvider');
+
+const useProviderSize = <T = SizeType>(props: Record<any, any>): ComputedRef<T> => {
+  const configProvider = inject<UnwrapRef<ConfigProviderProps>>(
+    'configProvider',
+    defaultConfigProvider,
+  );
+  const size = computed<T>(() => props.size || configProvider.componentSize);
+  provide(sizeProvider, size);
+  return size;
+};
+
+const useInjectSize = <T = SizeType>(): ComputedRef<T> => {
+  const size: ComputedRef<T> = inject(
+    sizeProvider,
+    computed(() => ('default' as unknown) as T),
+  );
+  return size;
+};
+
+export { useInjectSize, sizeProvider, useProviderSize };
+
+export default useProviderSize;
diff --git a/components/avatar/Avatar.tsx b/components/avatar/Avatar.tsx
index 46b6dbe12..29db24d16 100644
--- a/components/avatar/Avatar.tsx
+++ b/components/avatar/Avatar.tsx
@@ -7,16 +7,17 @@ import {
   inject,
   nextTick,
   onMounted,
-  onUpdated,
   PropType,
   ref,
   watch,
 } from 'vue';
-import { defaultConfigProvider } from '../config-provider';
 import { getPropsSlot } from '../_util/props-util';
 import PropTypes from '../_util/vue-types';
 import useBreakpoint from '../_util/hooks/useBreakpoint';
 import { Breakpoint, responsiveArray, ScreenSizeMap } from '../_util/responsiveObserve';
+import useConfigInject from '../_util/hooks/useConfigInject';
+import ResizeObserver from '../vc-resize-observer';
+import { useInjectSize } from '../_util/hooks/useSize';
 
 export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
 
@@ -44,6 +45,8 @@ export type AvatarProps = Partial<ExtractPropTypes<typeof avatarProps>>;
 const Avatar = defineComponent({
   name: 'AAvatar',
   props: avatarProps,
+  inheritAttrs: false,
+  slots: ['icon'],
   setup(props, { slots, attrs }) {
     const isImgExist = ref(true);
     const isMounted = ref(false);
@@ -52,12 +55,9 @@ const Avatar = defineComponent({
     const avatarChildrenRef = ref<HTMLElement>(null);
     const avatarNodeRef = ref<HTMLElement>(null);
 
-    const configProvider = inject('configProvider', defaultConfigProvider);
+    const { prefixCls } = useConfigInject('avatar', props);
 
-    const groupSize = inject(
-      'SizeProvider',
-      computed(() => 'default'),
-    );
+    const groupSize = useInjectSize();
 
     const screens = useBreakpoint();
     const responsiveSize = computed(() => {
@@ -82,7 +82,7 @@ const Avatar = defineComponent({
       return {};
     };
 
-    const setScale = () => {
+    const setScaleParam = () => {
       if (!avatarChildrenRef.value || !avatarNodeRef.value) {
         return;
       }
@@ -116,40 +116,35 @@ const Avatar = defineComponent({
       },
     );
 
+    watch(
+      () => props.gap,
+      () => {
+        nextTick(() => {
+          setScaleParam();
+        });
+      },
+    );
+
     onMounted(() => {
       nextTick(() => {
-        setScale();
+        setScaleParam();
         isMounted.value = true;
       });
     });
 
-    onUpdated(() => {
-      nextTick(() => {
-        setScale();
-      });
-    });
-
     return () => {
-      const {
-        prefixCls: customizePrefixCls,
-        shape,
-        size: customSize,
-        src,
-        alt,
-        srcset,
-        draggable,
-      } = props;
+      const { shape, size: customSize, src, alt, srcset, draggable } = props;
       const icon = getPropsSlot(slots, props, 'icon');
-      const getPrefixCls = configProvider.getPrefixCls;
-      const prefixCls = getPrefixCls('avatar', customizePrefixCls);
+      const pre = prefixCls.value;
       const size = customSize === 'default' ? groupSize.value : customSize;
       const classString = {
-        [prefixCls]: true,
-        [`${prefixCls}-lg`]: size === 'large',
-        [`${prefixCls}-sm`]: size === 'small',
-        [`${prefixCls}-${shape}`]: shape,
-        [`${prefixCls}-image`]: src && isImgExist.value,
-        [`${prefixCls}-icon`]: icon,
+        [`${attrs.class}`]: !!attrs.class,
+        [pre]: true,
+        [`${pre}-lg`]: size === 'large',
+        [`${pre}-sm`]: size === 'small',
+        [`${pre}-${shape}`]: shape,
+        [`${pre}-image`]: src && isImgExist.value,
+        [`${pre}-icon`]: icon,
       };
 
       const sizeStyle: CSSProperties =
@@ -162,9 +157,10 @@ const Avatar = defineComponent({
             }
           : {};
 
-      let children: VueNode = slots.default?.();
+      const children: VueNode = slots.default?.();
+      let childrenToRender;
       if (src && isImgExist.value) {
-        children = (
+        childrenToRender = (
           <img
             draggable={draggable}
             src={src}
@@ -174,42 +170,41 @@ const Avatar = defineComponent({
           />
         );
       } else if (icon) {
-        children = icon;
-      } else {
-        const childrenNode = avatarChildrenRef.value;
-
-        if (childrenNode || scale.value !== 1) {
-          const transformString = `scale(${scale.value}) translateX(-50%)`;
-          const childrenStyle: CSSProperties = {
-            msTransform: transformString,
-            WebkitTransform: transformString,
-            transform: transformString,
-          };
-          const sizeChildrenStyle =
-            typeof size === 'number'
-              ? {
-                  lineHeight: `${size}px`,
-                }
-              : {};
-          children = (
+        childrenToRender = icon;
+      } else if (isMounted.value || scale.value !== 1) {
+        const transformString = `scale(${scale.value}) translateX(-50%)`;
+        const childrenStyle: CSSProperties = {
+          msTransform: transformString,
+          WebkitTransform: transformString,
+          transform: transformString,
+        };
+        const sizeChildrenStyle =
+          typeof size === 'number'
+            ? {
+                lineHeight: `${size}px`,
+              }
+            : {};
+        childrenToRender = (
+          <ResizeObserver onResize={setScaleParam}>
             <span
-              class={`${prefixCls}-string`}
+              class={`${pre}-string`}
               ref={avatarChildrenRef}
               style={{ ...sizeChildrenStyle, ...childrenStyle }}
             >
               {children}
             </span>
-          );
-        } else {
-          children = (
-            <span class={`${prefixCls}-string`} ref={avatarChildrenRef} style={{ opacity: 0 }}>
-              {children}
-            </span>
-          );
-        }
+          </ResizeObserver>
+        );
+      } else {
+        childrenToRender = (
+          <span class={`${pre}-string`} ref={avatarChildrenRef} style={{ opacity: 0 }}>
+            {children}
+          </span>
+        );
       }
       return (
         <span
+          {...attrs}
           ref={avatarNodeRef}
           class={classString}
           style={{
@@ -218,7 +213,7 @@ const Avatar = defineComponent({
             ...(attrs.style as CSSProperties),
           }}
         >
-          {children}
+          {childrenToRender}
         </span>
       );
     };
diff --git a/components/avatar/Group.tsx b/components/avatar/Group.tsx
index 72b54c4c6..c88353919 100644
--- a/components/avatar/Group.tsx
+++ b/components/avatar/Group.tsx
@@ -6,6 +6,7 @@ import PropTypes from '../_util/vue-types';
 import { flattenChildren, getPropsSlot } from '../_util/props-util';
 import { tuple } from '../_util/type';
 import useConfigInject from '../_util/hooks/useConfigInject';
+import useProviderSize from '../_util/hooks/useSize';
 
 const groupProps = {
   prefixCls: PropTypes.string,
@@ -31,10 +32,8 @@ const Group = defineComponent({
   props: groupProps,
   inheritAttrs: false,
   setup(props, { slots, attrs }) {
-    const { prefixCls, direction, size } = useConfigInject('avatar-group', props);
-
-    provide('SizeProvider', size);
-
+    const { prefixCls, direction } = useConfigInject('avatar-group', props);
+    useProviderSize<AvatarSize>(props);
     return () => {
       const { maxPopoverPlacement = 'top', maxCount, maxStyle } = props;
 
diff --git a/components/config-provider/index.tsx b/components/config-provider/index.tsx
index 8a85799df..232012bb5 100644
--- a/components/config-provider/index.tsx
+++ b/components/config-provider/index.tsx
@@ -89,7 +89,7 @@ export const configProviderProps = {
     type: Object as PropType<{ ghost: boolean }>,
   },
   componentSize: {
-    type: Object as PropType<SizeType>,
+    type: String as PropType<SizeType>,
   },
   direction: {
     type: String as PropType<'ltr' | 'rtl'>,