73

I'm looking for a way of to do a cross-browser iphone-like badge in CSS3. I'd obviously like to use one div for this, but alternative solutions would be fine. The important factor is that it needs to be horizontally and vertically centered in all browsers.

An interesting design issue about these notifications is that they cannot have a specified width (height is fixed) - they should be able to handle [in ascii drawing] (1) and (1000), where (1000) is not a perfectly rounded circle, but instead looks more like a capsule.

EDIT: Additional constraints (from Steven):

  • No JavaScript
  • No mangling of the display property to table-cell, which is of questionable support status
Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
Matt
  • 22,224
  • 25
  • 80
  • 116

6 Answers6

135

Horizontal centering is easy: text-align: center;. Vertical centering of text inside an element can be done by setting line-height equal to the container height, but this has subtle differences between browsers. On small elements, like a notification badge, these are more pronounced.

Better is to set line-height equal to font-size (or slightly smaller) and use padding. You'll have to adjust your height to accomodate.

Here's a CSS-only, single <div> solution that looks pretty iPhone-like. They expand with content.

Demo: http://jsfiddle.net/ThinkingStiff/mLW47/

Output:

enter image description here

CSS:

.badge {
    background: radial-gradient( 5px -9px, circle, white 8%, red 26px );
    background-color: red;
    border: 2px solid white;
    border-radius: 12px; /* one half of ( (border * 2) + height + padding ) */
    box-shadow: 1px 1px 1px black;
    color: white;
    font: bold 15px/13px Helvetica, Verdana, Tahoma;
    height: 16px; 
    min-width: 14px;
    padding: 4px 3px 0 3px;
    text-align: center;
}

HTML:

<div class="badge">1</div>
<div class="badge">2</div>
<div class="badge">3</div>
<div class="badge">44</div>
<div class="badge">55</div>
<div class="badge">666</div>
<div class="badge">777</div>
<div class="badge">8888</div>
<div class="badge">9999</div>
ThinkingStiff
  • 64,767
  • 30
  • 146
  • 239
  • [How can I get to use this with a `draggable` event? The moment `class` is changed to `class="ui-widget-content"`, the entire functionality is gone out of line...](http://jsfiddle.net/mLW47/1242/) – bonCodigo Aug 14 '14 at 10:54
70

Modern Solution

The result is that the circle never gets distorted and the text stays exactly in the middle of the circle - vertically and horizontally.

.circle {
  background: gold;
  width: 40px; 
  height: 40px;
  border-radius: 50%;
  display: flex; /* or inline-flex */
  align-items: center; 
  justify-content: center;
}
<div class="circle">text</div>

Tailwind CSS

If you'd like to achieve the same using a modern framework - TailwindCSS. This is as simple as...

<div class="w-12 h-12 flex items-center justify-center bg-yellow-400 rounded-full">text</div>
Armand
  • 2,611
  • 2
  • 24
  • 39
6

If you have content with height unknown but you know the height the of container. The following solution works extremely well.

HTML

<div class="center-test">
    <span></span><p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. 
    Nesciunt obcaecati maiores nulla praesentium amet explicabo ex iste asperiores 
    nisi porro sequi eaque rerum necessitatibus molestias architecto eum velit 
    recusandae ratione.</p>
</div>

CSS

.center-test { 
   width: 300px; 
   height: 300px; 
   text-align: 
   center; 
   background-color: #333; 
}
.center-test span { 
   height: 300px; 
   display: inline-block; 
   zoom: 1; 
   *display: inline; 
   vertical-align: middle; 
 }
.center-test p { 
   display: inline-block; 
   zoom: 1; 
   *display: inline; 
   vertical-align: middle; 
   color: #fff; 
 }

EXAMPLE http://jsfiddle.net/thenewconfection/eYtVN/

One gotcha for newby's to display: inline-block; [span] and [p] have no html white space so that the span then doesn't take up any space. Also I've added in the CSS hack for display inline-block for IE. Hope this helps someone!

scott-pascoe
  • 1,463
  • 1
  • 13
  • 31
Richard Herries
  • 280
  • 3
  • 4
5

Interesting question! While there are plenty of guides on horizontally and vertically centering a div, an authoritative treatment of the subject where the centered div is of an unpredetermined width is conspicuously absent.

Let's apply some basic constraints:

  • No Javascript
  • No mangling of the display property to table-cell, which is of questionable support status

Given this, my entry into the fray is the use of the inline-block display property to horizontally center the span within an absolutely positioned div of predetermined height, vertically centered within the parent container in the traditional top: 50%; margin-top: -123px fashion.

Markup: div > div > span

CSS:

body > div { position: relative; height: XYZ; width: XYZ; }
div > div { 
  position: absolute;
  top: 50%;
  height: 30px;
  margin-top: -15px; 
  text-align: center;}
div > span { display: inline-block; }

Source: http://jsfiddle.net/38EFb/


An alternate solution that doesn't require extraneous markups but that very likely produces more problems than it solves is to use the line-height property. Don't do this. But it is included here as an academic note: http://jsfiddle.net/gucwW/

Steven
  • 17,796
  • 13
  • 66
  • 118
  • Absolutely great response! Unfortunately it's not quite there. Here's why: the container that vertically centers the `div > span` does not grow with new width. In your implementation would would think of the outermost div as the capsule, and the `div > span` as the text. You absolutely need the capsule to grow as you go from 1s to 10s, to 100s. Fantastic effort though! – Matt Jan 26 '11 at 03:55
  • What does 1s, 10s, 100s mean? – Steven Jan 26 '11 at 03:57
  • In ascii art - (1) to (10) to (100) notifications. Is that clear? – Matt Jan 26 '11 at 03:59
  • I'm afraid not. Can you edit my [first fiddle](http://jsfiddle.net/38EFb/) to demonstrate your case that breaks it? – Steven Jan 26 '11 at 04:01
  • Is the `table-cell` thing self-imposed? Because isn't `inline-block` in pretty much exactly the same position? I think everyone except IE6/7 supports `table-cell`. – sdleihssirhc Jan 26 '11 at 04:04
  • 1
    @sdlei: yes, it's self-imposed. The only reason for it is that I am personally uncomfortable using a property that is not very well [defined](http://www.w3.org/TR/CSS21/visuren.html#propdef-display) to begin with, and not at all defined outside of the context of a table. I have never studied in depth the consequences of using `display: table-cell` on non-table cell elements, although I welcome any education on the matter. – Steven Jan 26 '11 at 04:10
  • @Matt: it appears that I was not sufficiently clear on the purpose of `div.screen`. The `div` was meant to represent the viewport, *not* the border of the notice box. The specifics of your notice box are all meant to be contained within `span`. I have updated the code to this effect. I have added more semantic CSS classes and tweaked some values to match the "effect" of your updated test case, but if anything is unclear, feel free to ask. New code: http://jsfiddle.net/38EFb/5/ – Steven Jan 26 '11 at 05:39
2

Here is an example of flat badges that play well with zurb foundation css framework
Note: you might have to adjust the height for different fonts.

http://jsfiddle.net/jamesharrington/xqr5nx1o/

The Magic sauce!

.label {
  background:#EA2626;
  display:inline-block;
  border-radius: 12px;
  color: white;
  font-weight: bold;
  height: 17px; 
  padding: 2px 3px 2px 3px;
  text-align: center;
  min-width: 16px;
}
James Harrington
  • 3,138
  • 30
  • 32
0

Here's the code I used that ACTUALLY created a circle around my text

HTML

<!DOCTYPE html>
<html>
<head>
    <br></br><br></br><br></br><br></br><br></br>
    <title>Introducing CSS</title>
    <link href="CSS.css" type="text/css" rel="stylesheet" />
</head>
<body>
    <h1>
        <span class="three">Garden</span>
    </h1>
</body>
</html>

CSS

body {
    font-family: Arial, Verdana, sans-serif;
}
h1, h2 {
    color: #ee3e80;
}
p {
    color: #665544;
}

span {
    padding: 80px;
    background: gold;
    width: 40px; 
    height: 40px;
    border-radius: 100px;
    -moz-border-radius: 100px;
    -webkit-border-radius: 100px;
    display: flex;
    align-items: center; 
    justify-content: center;
    font-size: 1em
}
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
Victor
  • 1