CSS实现圆形头像效果

发布于 大漠

在Web开发中经常会碰到圆形图像的样式处理。在CSS中我们有很多种方式能实现圆形图形的效果,比如《聊聊CSS中的圆》一文中我们就介绍了很多种技术方案。在这些方案中有大家熟悉的border-radius,也有不熟悉的clip-path。这些制作圆形的方案都可以帮助我们实现圆形头像。在这篇文章中,我们就来看看圆形头像的实现方案。

圆形头像使用背景

圆形头像或者说圆形图形在Web的开发中是非常常见,特别是人物头像,很多时候都是以圆形(或带圆形边框的头像):

而源图像有正方形也有长方形,相对来说,正方形图像变成一个圆形要比长方形要容易地多,特别是希望图像正中心在圆心上。但对于长方形来说要难处理一点。在接下来的示例中,我们主要以长方形源图像为例,比如我们有一张像下面这样的图像:

使用border-radius实现圆形图像

制作圆形图像首先会想到border-radius,对于正方形的图像,在img自身上使用border-radius就能很好的实现圆形图像。

img {
    border-radius: 50%;
    width: 30vw;
}

从上图中我们可以发现img并不是正方形,这是图像源本来就不是一个正方形,img会按图像比例做自动缩放,具体的可以阅读《聊聊img元素》一文。

如果显式的给img设置widthheight属性值,有可能会给图像造成失真或扭曲,但我们可以使用object-fitobject-position来防止图像的失真,并且让图像中心原点在正中间:

img {
    border-radius: 50%;
    width: 30vmin;
    height: 30vmin;
    object-fit: cover;
    object-position: center;
}

在这种场景下要实现带有圆形边框的图像,可以直接使用border来实现:

有的开发者喜欢在<img>外面添加一个容器,通过图像的容器来控制正方形,并且在img上设置max-width: 100%按正方形的比例来实现圆形图像:

<!-- HTML -->
<div class="img__wrapper">
    <img src="https://static.fedev.cn/sites/default/files/blogs/2020/2004/css-circle-image-2.jpg" alt="">
</div>

// CSS
.img__wrapper {
    width: 30vmin;
    height: 30vmin;
    border-radius: 50%;
    overflow: hidden;
}

img {
    max-width: 100%;
    height: auto;
    object-fit: cover;
    object-position: center;
    border-radius: 50%;
}

另外,还可以给<img>设置绝对定位:

.img__wrapper {
    width: 30vmin;
    height: 30vmin;
    border-radius: 50%;
    overflow: hidden;
    position: relative;
}

.img__wrapper img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

使用background-image实现圆形头像

在Web中除了<img>元素添加图像之外,还可以使用background-image来添加图像。使用background-image实现圆形头像的关键是让元素自身是一个正方形,并且让背景图像居中显示。

<!-- HTML -->
<div class="img__wrapper"></div>

// CSS
.img__wrapper {
    width: 30vmin;
    height: 30vmin;
    border-radius: 50%;
    overflow: hidden;
    background: url('imgUrl') no-repeat center;
    background-size: cover;
}

为了让图片不扭曲,在使用background-image时最好添加background-size: cover(类似于object-fit: cover):

使用clip-path实现圆形头像

在CSS中,除了border-radius实现圆形之外,还可以使用clip-pathcircle()函数来绘制圆形。也就是说,我们在img或其容器上通过clip-path:circle()实现圆形头像。

<!-- HTML -->
<img src="https://static.fedev.cn/sites/default/files/blogs/2020/2004/css-circle-image-2.jpg" alt="" class="clip__path-1">

// CSS
.clip__path-1 {
    clip-path: circle(50% at center);
    width: 30vmin;
    height: 30vmin;
    object-fit: cover;
    object-position: center;
}

<!-- HTML -->
<div class="img__wrapper clip__path-2">
    <img src="https://static.fedev.cn/sites/default/files/blogs/2020/2004/cat-toes-paw-number-paws-tiger-tabby.jpg" alt="">
</div>

// CSS

.clip__path-2 {
    clip-path: circle(50% at center);
    width: 30vmin;
    height: 30vmin;
}

.clip__path-2 img {
    max-width: 100%;
    height: auto;
    object-fit: cover;
    object-position: center;
}

<!-- HTML -->
<div class="img__wrapper clip__path-3"></div>

// CSS
.clip__path-3 {
    width: 30vmin;
    height: 30vmin;
    clip-path: circle(50% at center);
    background: url("https://static.fedev.cn/sites/default/files/blogs/2020/2004/css-circle-image-2.jpg")
        no-repeat center;
    background-size: cover;
}

但使用clip-path绘制圆形头像时,头像带有边框的话就有所欠缺了:

有关于CSS clip-path更详细的介绍可以阅读《探索CSS Masking模块:Clipping》一文。

使用mask实现圆形头像

CSS中Clipping和Masking模块中除了clip-path之外还有mask属性。在mask-image中我们可以使用一个圆形的图形用来遮盖图像,从而创建一个圆形头像。

作为mask-image的圆形图像源除了使用图片之外还可以使用CSS的渐变来绘制一个圆形:

.circle {
    background-image: radial-gradient(circle, #456BD9, #456BD9 70%, transparent 70%);
    height: 5em;
    width: 5em;
}

这样来,我们可以将上面渐变绘制的圆形当作mask-image的图像源:

.mask {
    width: 30vmin;
    height: 30vmin;
    mask-image: radial-gradient(circle, #000, #000 70%, rgba(0, 0, 0, 0) 70%);
    mask-position: center;
    mask-size: cover;
}

使用mask要实现带有边框的圆形头像同样存在clip-path的现象。

使用SVG绘制圆形头像

除了上面提到的CSS方法之外,还可以使用SVG来绘制圆形头像:

<svg viewBox="0 0 200 200" width="200" height="200">
    <title>Avatar</title>
    <defs>
        <circle id="circle" cx="100" cy="100" r="100" vector-effect="non-scaling-stroke" />
        <clipPath id="circle-clip">
        <use xlink:href="#circle" />
        </clipPath>
    </defs>
    <g clip-path="url(#circle-clip)">
        <image xlink:href="https://static.fedev.cn/sites/default/files/blogs/2020/2004/cat-toes-paw-number-paws-tiger-tabby.jpg" width="100%" height="100%" preserveAspectRatio="xMidYMid slice" />
    </g>
</svg>

响应式圆形头像

我们再来看看响应式的头像效果怎么处理。

小站上有多篇文章介绍过元素宽高比相关的文章,简单地说,就是元素的高度如何根据宽度来变化。

在我们这个示例中,元素的宽和高都是相等的,即是一个正方形(不管是img自身还是其容器)。在CSS中,我们有很多种方式可以实现类似的效果,最简单的就是通过padding-bottom/top来实现,比如下面这个示例:

<!-- HTML -->
<div></div>

// CSS
div {
    width: 30vmin;
}

div::before {
    content: "";
    display: block;
    width: 100%;
    height: 0;
    padding-bottom: 100%;
    background: #f36;
}

基于这个,就可以很容易实现响应式的圆形头像:

.wrapper {
    width: 30vmin;
    min-width: 20vmin;
    max-width: 80vmin;
    overflow: hidden;
    resize: horizontal;
    border-radius: 50%;
    position: relative;
}

.wrapper::before {
    content: "";
    display: block;
    width: 100%;
    height: 0;
    padding-bottom: 100%;
    background: #f36;
}

.wrapper img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: auto;
    object-fit: cover;
    object-position: center;
}

使用React构建Avatar组件

根据上面的示例,我们可以封装一个React组件,比如Avatar。创建一个Avatar组件:

// src/components/Avatar/index.tsx
import * as React from 'react'

interface AvatarProps {
    src: string;
    width: string;
    radius: string;
    altDes: string;
}

const Avatar = (props: AvatarProps) => {
    const { src, width, radius, altDes, ...rest } = props

    const avatarInnerStyle = {
        width: '100%',
        height: '0',
        paddingBottom: '100%',
        position: 'relative',
        overflow: 'hidden',
        borderRadius: `${radius}`,
    } as React.CSSProperties;

    const imgStyle={
        position: `absolute`,
        top: `0`,
        left: `0`,
        width: `100%`,
        height: `auto`,
        objectFit: `cover`,
        objectPosition: `center`,
    } as React.CSSProperties;

    return <div className="avatar" {...rest} style={{width:`${width}`}}>
    <div className='avatar__inner' style={avatarInnerStyle}>
        <img src={src} alt={altDes} style={imgStyle} />
        </div> 
    </div>
}

export default Avatar

在需要的地方像下面这样调用Avatar组件:

<Avatar 
    src="https://static.fedev.cn/sites/default/files/blogs/2020/2004/cat-toes-paw-number-paws-tiger-tabby.jpg" 
    width="200px"
    altDes="avatar"
    radius='50%'
/>

我们创建了一个响应式的Avatar组件。

我们再来看一个Vue构建的Avatar组件:

有关于这方面更多的组件还可以查阅:

小结

圆形头像在Web中使用场景很多,文章中向大家介绍了多种实现圆形头像的实现方案,而且每种方案都有其自身的优势。最后封装了一个简单的响应式的Avatar组件。如果你在这方面有更好的建议或经验,欢迎在下面的评论中与我们共享。