简体   繁体   中英

Make a perfect circle around a div of variable height

I've looked into this a fair bit but can't seem to find a good, solid answer to find how to make a responsive circle around a div element of variable height.

It's easy to make a simple responsive circle using vw units.

<div style="height:20vw; width:20vw"></div>

However, I'm looking to use a min-height of an element and have a circle around this div.

Another way to create a responsive circle is using something like the snippet below, but again I can't adapt this to work for a variable height (again, I can't use vh units as the div will change in height.

 .square { position: relative; width: 10%; background: gray; border-radius: 50%; }.square:after { content: ""; display: block; padding-bottom: 100%; }.content { position: absolute; width: 100%; height: 100%; }
 <div class="square"> <div class="content"> </div> </div>

I am trying to create something like the below, where the circle will never cut into the corners of the div (with around a 10px padding). I personally was trying to avoid javascript and would have preferred a css only approach, but it seems it's unavoidable. Maybe the only solution is to use a jquery to calculate the height of the element in order to apply this to a wrapper element?

在此处输入图像描述

I was playing around with this:

 .square { position: absolute; top: 50%; display: inline-block; left: 50%; transform: translate(-50%, -50%); min-height: 100px; border-radius: 50%; background: url('https://i.imgur.com/2dxaFs9_d.webp?maxwidth=640&shape=thumb&fidelity=medium'); background-size: 100% 100%; padding: 20px; }.content { width: 300px; min-height: 100px; background: tomato; }
 <div class="square"> <div class="content"> Hello!<br> <br><br><br>This has a variable height but fixed width<br><br><br>Hello </div> </div>

Clip-path can easily do this if you consider solid coloration.

Resize the element and the circle will follow:

 .box { width: 200px; height: 200px; overflow: hidden; resize: both; background: blue; box-shadow: 0 0 0 200vmax red; clip-path: circle(71%); margin: 100px auto; }
 <div class="box"></div>

Related question to understand the magic number 71% : clip-path:circle() radius doesn't seem to be calculated correctly


To use an image we can consider pseudo elements. You can also rely on calc() to add the offset:

 .box { width: 200px;= resize: both; clip-path: circle(calc(71% + 10px)); margin: 100px auto; position: relative; font-size:35px; color:#fff; } /* the background layer */.box::before { content:""; position: absolute; z-index:-1; top:0; left:0; right:0; bottom:0; background:blue; } /* the image layer */.box::after { content:""; position: fixed; /* to make sure the image cover all the screen */ z-index:-2; top:0; bottom:0; left:0; right:0; background:url(https://picsum.photos/id/1015/1000/1000) center/cover no-repeat; }
 <div class="box" contenteditable="true"> Edit this<br>text </div>

I tried my hardest to figure this out with pure css. Though the problem with css I could not figure out how to calculate the diameter of the circle based on the content div size; the length from top left corner to bottom right corner of the variable height div.

I'm not sure if can be done using the calc() css function.

But I did manage to do it with a little jquery (which could easily be changed to pure javascript if you are not using jquery).

See working resizable example below (follow my comments in code)

Note: If you are using internet explorer the resizable demo content div will not resize.

 // circumscriber for variable size divs function circumscriber() { // for each variable size div on page $(".variable-size").each(function() { // get the variable size div content width and height let width = $(this).outerWidth(); let height = $(this).outerHeight(); // get the diameter for our pefect circle based on content size let diameter = Math.sqrt(width ** 2 + height ** 2); // extra 15 pixel circle edge around variable size div let edge = 15; // add current circle size width css $('.circle', this).css({ 'width': (diameter + (edge * 2)) + 'px' }) }); } // run the circumscriber (you might wana do this on ready) circumscriber(); // if the window is resized responsively $(window).on('resize', function() { circumscriber(); }); // for demo purpose to fire circumscriber when resizing content // not needed for real thing $('.content').on('input', function() { this.style.height = ""; this.style.height = ( this.scrollHeight - 30 ) + "px"; circumscriber(); }).on('mouseup', function() { circumscriber(); });
 /* variable size container to be circumscribed by circle */ /* none of these styles are required, this just to center the variable size div in the window for demo purposes */.variable-size { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } /* resizable text area for demo */ /* again not needed */.variable-size.content { padding: 15px; background: #fff; resize: both; overflow: auto; color: #000; border: none; width: 200px; font-weight: bold; }.variable-size.content:focus { outline: 0; } /* child circle div css */.variable-size.circle { position: absolute; background-image: url('https://i.imgur.com/2dxaFs9_d.webp?maxwidth=640&shape=thumb&fidelity=medium'); background-position: center center; z-index: -1; border-radius: 50%; left: 50%; top: 50%; transform: translate(-50%, -50%); transition: all 0.5s ease; width: 0; } /* fast way to make circle height the same as current width */.variable-size.circle:before { display: block; content: ''; width: 100%; padding-top: 100%; } /* demo window css */ HTML, BODY { height: 100%; min-height: 100%; background: black; position: relative; font-family: "Lucida Console", Courier, monospace; }
 <div class="variable-size"> <textarea class="content" rows="1" placeholder="TYPE TEXT OR RESIZE ME &#8600;"></textarea> <div class="circle"></div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


See jsfiddle here... https://jsfiddle.net/joshmoto/6d0zs7uq/

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(100, 75, 50, 0, 2 * Math.PI);
ctx.stroke();

Source: https://www.w3schools.com/

You could use flex display and insert empty flex-items around the inner div and use flex-basis to fix their width.

Try this

 .square { display: flex; justify-content: center; align-items: center; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); min-height: 100px; border-radius: 50%; background: black; background-size: 100% 100%; padding: 20px; }.content { width: 300px; min-height: 100px; background: tomato; }.emptyDiv { flex-basis: 120px }
 <div class="square"> <div class="emptyDiv"></div> <div class="content"> Hello!<br> <br><br><br>This has a variable height but fixed width<br><br><br>Hello </div> <div class="emptyDiv"></div> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM