jbutler483
jbutler483

Reputation: 24559

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?

enter image description here

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>

Upvotes: 3

Views: 3103

Answers (4)

Temani Afif
Temani Afif

Reputation: 272919

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>

Upvotes: 6

joshmoto
joshmoto

Reputation: 5088

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/

Upvotes: 2

alchemist95
alchemist95

Reputation: 794

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>

Upvotes: -3

Ashish
Ashish

Reputation: 643

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/

Upvotes: -3

Related Questions