透明的空心或切出的圆圈

Posted

技术标签:

【中文标题】透明的空心或切出的圆圈【英文标题】:Transparent hollow or cut out circle 【发布时间】:2012-01-07 08:43:33 【问题描述】:

是否可以仅使用 CSS切出一个空心圆

这是我们都可以做到的:

但是我们可以这样做吗?

圆圈必须是空心透明的。因此,通过在div 上放置一个纯色圆圈并不能解决问题。

【问题讨论】:

通过'only CSS'大概你更喜欢不使用图片/image-masks? 我想这样做,但使用带有背景图像的元素,而不仅仅是纯色。这可能吗? 【参考方案1】:

您可以使用 2 种不同的技术实现透明切割圆

1.SVG

以下示例使用inline svg。第一个 sn-p 使用mask element 切出透明圆,第二个空心圆使用path element。圆圈由 2 arc commands 组成:

带遮罩元素:

bodybackground:url('https://farm9.staticflickr.com/8760/17195790401_ceeeafcddb_o.jpg');background-size:cover;
<svg viewbox="0 0 100 50" >
  <defs>
    <mask id="mask" x="0" y="0"  >
      <rect x="5" y="5"   fill="#fff"/>
      <circle cx="50" cy="25" r="15" />
    </mask>
  </defs>
  <rect x="0" y="0"   mask="url(#mask)" fill-opacity="0.7"/>    
</svg>

只有一个路径元素:

bodybackground: url('https://farm9.staticflickr.com/8760/17195790401_ceeeafcddb_o.jpg');background-size:cover;
svg
  display:block;
  width:70%;
  height:auto;
  margin:0 auto;

path
  transition:fill .5s;
  fill:#E3DFD2;

path:hover
  fill:pink;
<svg viewbox="-10 -1 30 12">
  <path d="M-10 -1 H30 V12 H-10z M 5 5 m -5, 0 a 5,5 0 1,0 10,0 a 5,5 0 1,0 -10,0z"/>
</svg>

在这种情况下使用 SVG 的主要优点是:

更短的代码 您可以轻松地使用图像或渐变来填充圆形蒙版 保持形状的边界并仅在与蒙版相关的填充上触发鼠标事件(悬停在示例中的透明剪切圆

2。 CSS 仅使用 BOX-SHADOWS

使用overflow:hidden; 创建一个div,并在其中创建一个带有border-radius 的圆形伪元素。给它一个巨大的盒子阴影并且没有背景:

div
    position:relative;
    width:500px; height:200px;
    margin:0 auto;
    overflow:hidden;

div:after
    content:'';
    position:absolute;
    left:175px; top:25px;
    border-radius:100%;
    width:150px; height:150px;
    box-shadow: 0px 0px 0px 2000px #E3DFD2;


bodybackground: url('https://farm9.staticflickr.com/8760/17195790401_ceeeafcddb_o.jpg');background-size:cover;
&lt;div&gt;&lt;/div&gt;

对 box-shadows 的浏览器支持是 IE9+,请参阅 canIuse

同样的方法是使用边框而不是框阴影。如果您需要支持不支持像 IE8 这样的 box-shadows 的浏览器,这很有趣。技术是一样的,但是你需要用 top 和 left 值来补偿,以使圆保持在 div 的中心:

body
    background: url('https://farm9.staticflickr.com/8760/17195790401_ceeeafcddb_o.jpg');
    background-size:cover;

div
    position:relative;
    width:500px; height:200px;
    margin:0 auto;
    overflow:hidden;

div:after
    content:'';
    position:absolute;
    left:-325px; top:-475px;
    border-radius:100%;
    width:150px; height:150px;
    border:500px solid #E3DFD2;
&lt;div&gt;&lt;/div&gt;

【讨论】:

非常感谢你的 box-shadow,天哪,我怎么没想到那个! :/我知道可以使用一些超出边界的圆圈来完成。但你成功了! 注意如果在 Safari 中使用 box-shadow .. 它们是不可见的,但边框是可见的。请改用它们。【参考方案2】:

可以使用radial gradient 背景和指针事件来完成(允许鼠标通过圆圈层进行交互,例如文本选择)。这是a demo page 和截图:

这就是它的代码:

<!DOCTYPE html>

<html>
<head>
<meta charset="UTF-8">
<style type="text/css" media="screen">
body 
  margin: 0;
  padding: 0;


.underneath 
  padding: 0;
  margin: 265px 0 0 0;
  width: 600px;


.overlay 
  top: 0;
  left: 0;
  position: absolute;
  width: 600px;
  height: 600px;
  background: -moz-radial-gradient(transparent 150px, rgba(0,0,0,1) 150px);
  background: -webkit-radial-gradient(transparent 150px, rgba(0,0,0,1) 150px);
  background: -ms-radial-gradient(transparent 150px, rgba(0,0,0,1) 150px);
  background: -o-radial-gradient(transparent 150px, rgba(0,0,0,1) 150px);
  pointer-events: none; /* send mouse events beneath this layer */

</style>
</head>
<body>

<p class="underneath">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
  incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
  nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
  Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore
  eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt
  in culpa qui officia deserunt mollit anim id est laborum.
</p>

<div class="overlay"></div>

</body>
</html>

【讨论】:

@chris 不客气。如果您对矩形穿透窗口感兴趣,我前段时间发布了类似的答案:***.com/questions/7979675/… 然而,这给出了一个边缘非常“粗糙”的圆,所以如果有人有一个解决方案可以产生一个很好渲染的穿透圆,那么它是非常受欢迎的。 @chris 如果圆圈的大小是固定的,则使用居中的背景图像,但保留pointer-events 部分。如果大小不同,那么您可以使用 SVG 为 WebKit developer.mozilla.org/en/CSS/-webkit-mask 和 Firefox developer.mozilla.org/En/Applying_SVG_effects_to_HTML_content 创建掩码 @BenRacicot 小提琴没有坏。在此处查看复制粘贴:output.jsbin.com/wibiyawawi @IonuțG.Stan,谢谢你的回答。但它可以与图像结合吗?所以不是黑色而是被图像掩盖?【参考方案3】:

参考 web-tiki 的回答,我想补充一点,您始终可以使用 translate(-50%,-50%) 将 div 居中,因此使用 border-property 没有问题,它具有更好的浏览器支持。

div
    position:relative;
    width:500px; 
    height:200px;
    margin:0 auto;
    overflow:hidden;

div:after
    content:'';
    position:absolute;
    left:50%;
    top: 50%;
    transform: translate(-50%,-50%);
    border-radius:50%;
    width:150px; height:150px;
    border: 1000px solid rebeccapurple;


bodybackground: url('https://farm9.staticflickr.com/8760/17195790401_ceeeafcddb_o.jpg');background-size:cover;
&lt;div&gt;&lt;/div&gt;

您可以通过这种技术获得真正的创意:

document.addEventListener( "DOMContentLoaded", function() 
	setInterval(function()
		if(document.getElementById("moving").style.height === "500px")
			document.getElementById("moving").style.height = "0px";
		 else 		
			document.getElementById("moving").style.height = "500px";
		
	, 2000);
);
#container 
	width: 500px;
	margin: 0 auto;
	border: 1px solid black;
	overflow:hidden;
	position: relative;



#circle
    position:relative;
    height:150px;
    margin:0 auto;
	clear:left;
	overflow:hidden;

#circle::before, #circle::after 
    content:'';
    border-radius:50%;
	position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);

#circle::before 
    height: 140px;
    width: 140px;
    background: rebeccapurple;

#circle::after
    width:150px; 
	height:150px;
    border: 2000px solid rebeccapurple;


#line 
	margin: 0 auto;
	width: 6px;
	height: 200px;
	position: relative;

#line::before, #line::after 
	content: " ";
	background-color: rebeccapurple;
    height: 200px;
	width:2000px;
	position:absolute;

#line::before 
	right: 100%;

#line::after  
	left: 100%;


#moving 
	height: 0px;
    width: 100%;
    background: blue;
    transition: 2s height;
    position: absolute;
    top: 0px;
    z-index: -1;

body
	background: url('https://farm9.staticflickr.com/8760/17195790401_ceeeafcddb_o.jpg');background-size:cover;
<div id="container">
	<div id="circle"></div>
	<div id="line"></div> 
    <div id="circle"></div>
    <div id="moving"></div>
</div>

【讨论】:

对于像我这样挣扎的人 - div:after 需要 box-sizing: content-box;有时由 css 框架设置为边框。【参考方案4】:

关于“Pius Nyakoojo”中的“方法 1”,稍作改进(见下文)它会起作用。我个人认为这是最简单的解决方案:

<html>
<!-- Assuming the stuff to mask is a 100 pixel square -->
<style>
.mask 
    position: absolute;
    top: -50px;                     /* minus half the div size */
    left: -50px;                    /* minus half the div size */
    width: 100px;                   /* the div size */
    height: 100px;                  /* the div size */
    background-color: transparent;
    border-radius: 100px;           /* the div size */
    border: 50px solid white;       /* half the div size */
    pointer-events: none;           /* send mouse events beneath this layer */


.stuff 
    position: absolute;
    width: 100px;                   /* the div size */
    height: 100px;                  /* the div size */
    overflow: hidden;               /* hide the excess of the mask border */
    background-color: #CCC;

</style>
<body>
    <div class="stuff">
        <div class="mask"></div>
        blah blah blah blah blah
        blah blah blah blah blah
        blah blah blah blah blah
    </div>
</body>
</html>

【讨论】:

【参考方案5】:

方法1- 首选

<div class="circle"></div>
$radius: 50px;
$thickness: 5px;

.circle 
    width: $radius;
    height: $radius;
    background-color: transparent;
    border-radius: $radius;
    border: $thickness solid gray;

方法二

<div class="circle"></div>
$radius: 50px;
$thickness: 5px;

.circle 
  width: $radius;
  height: $radius;


.circle::before, .circle::after 
  margin: -2px 0;

.circle::before 
    content: '';
    display: inline-block;
    width: $radius;
    height: calc(#$radius / 2);
    background-color: transparent;
    border-top-left-radius: calc(#$radius / 2);
    border-top-right-radius: calc(#$radius / 2);
    border: $thickness solid gray;
    border-bottom: 0;

    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;


.circle::after 
  content: '';
  display: inline-block;
  width: $radius;
  height: calc(#$radius / 2);
  background-color: transparent;
  border-bottom-left-radius: calc(#$radius / 2);
  border-bottom-right-radius: calc(#$radius / 2);
  border: $thickness solid gray;
  border-top: 0;

  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;

【讨论】:

方法1不只是创建一个边框吗?圆圈外的整个区域都应该涂上颜色。不仅仅是边界。【参考方案6】:

您可以使用 css 蒙版和额外的 svg 图片来做到这一点。Although browser support is weak

body 
  background: url(https://data.whicdn.com/images/50959200/original.jpg);
  background-size: cover;
  background-position: center;


.circle 
  width: 150px;
  height: 150px;
  background: black;
  border-radius: 50%;
  -webkit-mask: url(https://svgshare.com/i/GLf.svg);
  -webkit-mask-size: 125%; /* change it */
  -webkit-mask-position: center;
  margin: 20px auto;
&lt;div class="circle"&gt;&lt;/div&gt;

【讨论】:

【参考方案7】:

我们可以使用radial-gradientmask 来做到这一点。使用单个 div,没有伪元素。

* 
  box-sizing: border-box;


html,
body 
  height: 100%;


body 
  margin: 0;
  background-image: url(https://picsum.photos/id/1060/720/1280);
  background-size: cover;


.a 
  /* this is flexible. you can change */
  --circle-radius: 100px;
  height: 100%;
  width: 100%;
  --mask: radial-gradient(circle farthest-side at center center, transparent var(--circle-radius), #000 calc(var(--circle-radius) + 2px) 100%) 50% 50%/100% 100% no-repeat;
  -webkit-mask: var(--mask);
          mask: var(--mask);
  background: #000;
&lt;div class="a"&gt;&lt;/div&gt;

圆半径也可以是百分比值:

* 
  box-sizing: border-box;


html,
body 
  height: 100%;


body 
  margin: 0;
  padding: 30px;
  background-image: url(https://picsum.photos/id/1060/720/1280);
  background-size: cover;


.a 
  --circle-radius: 20%; /* changed as percent value */
  
  height: 100%;
  width: 100%;
  --mask: radial-gradient(circle farthest-side at center center, transparent var(--circle-radius), #000 calc(var(--circle-radius) + 2px) 100%) 50% 50%/100% 100% no-repeat;
  -webkit-mask: var(--mask);
          mask: var(--mask);
  background: rgba(0, 0, 0, .8);
&lt;div class="a"&gt;&lt;/div&gt;

另一个想法:

* 
  box-sizing: border-box;


html,
body 
  height: 100%;


body 
  margin: 0;
  background-image: url(https://picsum.photos/id/1060/720/1280);
  background-size: cover;


.a 
  --circle-radius: 100px;
  --border-width: 30px;
  
  height: 100%;
  width: 100%;
  --mask: radial-gradient(circle farthest-side at center center, transparent var(--circle-radius), #000 calc(var(--circle-radius) + 2px) calc(var(--circle-radius) + 2px + var(--border-width)), transparent calc(var(--circle-radius) + 2px + var(--border-width) + 2px) 100%) 50% 50%/100% 100% no-repeat;
  -webkit-mask: var(--mask);
          mask: var(--mask);
  background: #000;
&lt;div class="a"&gt;&lt;/div&gt;

反向:

* 
  box-sizing: border-box;


html,
body 
  height: 100%;


body 
  margin: 0;
  background-image: url(https://picsum.photos/id/1060/720/1280);
  background-size: cover;


.a 
  --circle-radius: 100px;
  --border-width: 30px;
  
  height: 100%;
  width: 100%;
  --mask: radial-gradient(circle farthest-side at center center, #000 var(--circle-radius), transparent calc(var(--circle-radius) + 2px) calc(var(--circle-radius) + 2px + var(--border-width)), #000 calc(var(--circle-radius) + 2px + var(--border-width) + 2px) 100%) 50% 50%/100% 100% no-repeat;
  -webkit-mask: var(--mask);
          mask: var(--mask);
  background: #000;
&lt;div class="a"&gt;&lt;/div&gt;

【讨论】:

以上是关于透明的空心或切出的圆圈的主要内容,如果未能解决你的问题,请参考以下文章

从背景中切出的透明文本

Sketch 如何快速切出背景透明且留边的切图?

有没有办法让半透明的圆圈背景完全透明,中间是完全不透明的盒子?

透明背景 UIView drawRect 圆圈

显示半透明圆圈的快速动画

Android Canvas:仅在透明背景上绘制圆圈