Why are images centered vertically with `line-height` positioned 2 pixels below where they should be?
Asked Answered
E

2

11

Short story:

jsfiddle here. The behavior is consistently wrong in Chrome 21, Firefox 15 and IE9, which makes me think I'm misunderstanding something about the CSS spec.

Longer story:

I want to center an image vertically using line-height. I've set the height of the image container equal to the line-height, I've reset margins, paddings and borders for all elements, yet the image is 2 pixels below where it should be. This happens whether the image is smaller than the container, or larger than it (in which case I used max-width: 100; max-height: 100% to size it down).

The image has an even number of pixels in both cases. I wouldn't care that much for images smaller than the container, but for images that are larger, a 2-pixel line from the container background will bleed through at the top of the image.

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Images centered vertically with line-height have center miscalculated by 2 pixels</title>

    <style type="text/css">
        * { margin: 0; padding: 0; border: 0px solid cyan; }  /* reset all margins, paddings and borders */
        html {
            font-size: 16px;
            line-height: normal;
        }
        body {
            line-height: 100%;
            background: gray;
        }
        .img-wrapper-center {
            width: 400px;
            height: 200px;  /* necessary, besides line-height, if images are taller than it */
            line-height: 200px;  /* must be equal to line-height */
            text-align: center;
            background: white;
        }
        .img-wrapper-center img {
            vertical-align: middle;
            /* Comment the two rules below. The first image will still be mis-aligned by two pixels, but the second will not. */
            max-width: 100%; max-height: 100%;  /* force scaling down large images */
        }

    </style>
</head>

<body>

    <div class="img-wrapper-center" id="div1">
        <img src="http://gravatar.com/avatar" id="img1"/>  <!-- 80x80 -->
    </div>

    <div class="img-wrapper-center" id="div2" style="background: green">
        <img src="http://www.w3.org/html/logo/img/class-header-semantics.jpg" id="img2" />  <!-- 495x370 -->
    </div>

    <p>
    Note how the second image is misaligned down by two pixels.
    The first one is mis-aligned the same way. Sizes and coordinates are below.
    </p>

    <script>
        document.writeln('div1 top: ' + document.getElementById('div1').offsetTop + '<br/>');
        document.writeln('image 1 height: ' + document.getElementById('img1').offsetHeight + '<br/>');
        document.writeln('div1 height: ' + (document.getElementById('div1').offsetHeight) + '<br/>');
        document.writeln('image 1 top should be at: ' + (document.getElementById('div1').offsetHeight - document.getElementById('img1').height) / 2 + '<br/>');
        document.writeln('image 1 top actually is at: ' + document.getElementById('img1').offsetTop + '<br/>');
        document.writeln('div2 top: ' + document.getElementById('div2').offsetTop + '<br/>');
        document.writeln('img2 top: ' + document.getElementById('img2').offsetTop + '<br/>');
    </script>

</body>
</html>
Ethanol answered 4/9, 2012 at 8:39 Comment(2)
have you tried your various combinations without the "vertical-align: middle" rule?Doctrinaire
Common issue with inline image that I never cared to look up if there is something in the spec about it. Usually I can bypass the problem by setting the image to display block and set a margin:0 auto;. But this method does not allow you to have a fluid vertical allign(only if you know the height measurements). jsfiddle.net/8UaUQPrittleprattle
L
9

You have to set zero font-size for container div elements. Because images are displayed as inline elements they are affected by text in container div. Zero font-size fixes this:

.img-wrapper-center
{
    font-size:0;
}

Here is fiddle: http://jsfiddle.net/bZBsR/

Lucy answered 4/9, 2012 at 8:53 Comment(0)
M
0

If you also have text inside this div you can use this property:

.img-wrapper-center {
    display: flex;
    justify-content: center;
}

Here is fiddle: https://jsfiddle.net/rjurado/yvanL4k1/2/

Madea answered 10/5, 2017 at 10:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.