17

I have a list of elements and upon a specific action, i'd like to apply the css-transform translate to move it into the center of the window. I know css-transform is used to relatively move an element, but I was wondering whether it is possible to anchor it absolutely somewhere, i.e. in the middle of the window (lightbox-style). I'm looking at an animation similar to the iPad Music app, where the album cover flips and centers.

Note: I want to use css-transforms because it avoids reflow of surrounding elements.

Nam

Edit: I have created a JSfiddle for better illustration: http://jsfiddle.net/bdtZc/, relevant line:

.card:focus {
   -webkit-transform: rotateY(180deg);
}
nambrot
  • 2,551
  • 2
  • 19
  • 31
  • maybe this help [How to Create a Responsive Centered Image in CSS3](http://cssdeck.com/labs/full/responsive-image) . They use `transform: translate(-50%, -50%);` – furas May 23 '13 at 21:33
  • What action, Jquery, css hover?? – Cam May 23 '13 at 21:36
  • @Cam, i currently try to do it on css:focus, i want to avoid js and have a css only solution – nambrot May 23 '13 at 21:49
  • You could easily just do postion: absolute; left: 50%; top: 50% – Cam May 23 '13 at 21:50
  • I just tried, but if you change positioning, it interrupts the flipping animation of the card? It will also force reflow as far as i can see. I assume there is no solution to my problem – nambrot May 23 '13 at 21:58

4 Answers4

19

Update 2017

Since I just received another upvote for this answer I thought I'd revisit it.

With current browsers you should have good luck with the transform(-50%, -50%) technique from other answers but depending on how your content containers are set up that may not result in the center of the window; it may be the center of your container which could be smaller or larger than the window.

The latest browsers support viewport units (vh, vw) which would give you exactly what you're looking for as far as viewport centering. Animation from current location to viewport center would be a different issue due to scrolling.

http://caniuse.com/#feat=viewport-units https://developer.mozilla.org/en-US/docs/Web/CSS/length (see vh, vw)

Without CSS Transform

You can accomplish this without using css-transform by using absolute positioning:

(full code here : http://jsfiddle.net/wkgWg/ )

.posDiv
{
    position:absolute;
    top:0;
    left:0;
    margin:0;
    border:1px solid red;

    -moz-transition:all 2s;
    -webkit-transition:all 2s;
    -o-transition:all 2s;
    transition:all 2s;
}

.triggerElement:hover .posDiv
{
    top:50%;
    left:50%;
    margin-left:-50px;
    margin-top:-50px;

    -moz-transition:all 2s;
    -webkit-transition:all 2s;
    -o-transition:all 2s;
    transition:all 2s;
}

With CSS Transform

If you'd like to continue working with CSS-Transform, you'll need to calculate the "center" or the end location of your transform using JavaScript and then generate and attach a transform statement at runtime. Your origin transform vector would need to be subtracted from the "center to screen" vector.

Here's a javascript version using css-transform (where supported) via the jQuery.transit plugin by Rico Sta. Cruz.

(Full fiddle here: http://jsfiddle.net/ZqpGL/263/ )

$(function() {
    var $cards = $('.card');
    var cardInFocus = null;


    $cards.each(function(index, elem) {
        var $elem = $(elem);
        var pos = $elem.position();
        $(elem).data('orig-x', pos.left);
        $(elem).data('orig-y', pos.top);
    });

    var reset = function() {
        if (cardInFocus) {
            $(cardInFocus).transition({
                x: 0,
                y: 0
            });
        }
    };

    $cards.on('focus', function(e) {
        reset();
        cardInFocus = this;
        var $doc = $(document);
        var centerX = $doc.width() / 2;
        var centerY = $doc.height() / 2;
        var $card = $(this);
        var origX = $card.data('orig-x');
        var origY = $card.data('orig-y');
        $(this).transition({
            x: centerX - origX,
            y: centerY - origY
        });
    });

    $cards.on('blur', function(e) {
        reset();
    });

});
TheCrazyProfessor
  • 919
  • 1
  • 15
  • 31
Ryan Rahlf
  • 1,772
  • 1
  • 14
  • 15
  • 1
    Yes I can do that with absolute positioning, but the point was that this is not desirable due to positioning change and reflow – nambrot May 23 '13 at 22:05
  • I've updated my answer with a css-transform version. – Ryan Rahlf May 24 '13 at 17:58
  • For this approach you need to know the size of the element, so it have to be fixed sized or you need javascript to calculate the size. [This approach](http://stackoverflow.com/a/22234108/2590616) with transform: translate(-50%, -50%) is more elegant and has better performance. – RiZKiT Feb 25 '16 at 08:27
  • do you have a "With CSS Transform" without jQuery or just without any plugins – TheCrazyProfessor Dec 13 '18 at 12:29
12

An article at CSS-Tricks (http://css-tricks.com/centering-percentage-widthheight-elements/) pointed out that one could use a mixture of absolute positioning and translation, without resorting to the use of JS.

This helps to limit reflow, and keeps your element centered even during size changes to the element or the screen.

.center {
    position: absolute;
    left: 50%;
    top: 50%;

    /*
    Nope =(
    margin-left: -25%;
    margin-top: -25%;
    */

    /* 
    Yep!
    */
    transform: translate(-50%, -50%);

    /*
    Not even necessary really. 
    e.g. Height could be left out!
    */
    width: 40%;
    height: 50%;
}
pouncyisdead
  • 121
  • 1
  • 4
  • Thanks for sharing the link and technology. I like this css only and top performance solution very much. Browser support for transform2d: http://caniuse.com/#feat=transforms2d Link to demo: http://tympanus.net/Development/ModalWindowEffects/ – RiZKiT Feb 25 '16 at 08:30
10

You can do it in pure CSS now with the vh (view height) unit. It's always relative to the screen size, not the element itself:

/* position element in middle of screen */
translateY(calc(50vh))

So if you know the height of the element (say height:320px), you can move it exactly to the center of the screen.

/* moves the element down exactly off the bottom of the screen */
translateY(calc(50vh - 160px))
phreakhead
  • 14,721
  • 5
  • 39
  • 40
  • 3
    or just `translateY(calc(50vh - 50%))` – illnr Dec 03 '17 at 16:16
  • Although this answer is too old, but I -1'ed because translate "moves", it doesn't position. so this only works if the element is already at (0, 0), otherwise it will just expand the page. – aderchox May 08 '22 at 12:17
0

I would recommend looking into a JS solution for this, as this will be problematic for images of different sizes, but since you asked for a CSS solution...

You could use keyframe animation for this effect like so: jsFiddle

.card:focus {
    transition:all 2s;
    position: absolute;
    animation: center 3s forwards;
}

@keyframes center {
    0% {
        top:0%;
        left:0%;
    }
    100% {
        top:45%;
        left:45%;
        -webkit-transform: rotateY(180deg);
        transform: rotateY(180deg);
    }
}

Edit: Here's a rough better jQuery version using

position:relative;

jsFiddle

$('.card').focusin(function () {
    var tc = $(window).height() / 2 - $('.card').height() / 2;
    var lc = $(window).width() / 2 - $('.card').width() / 2 - $(this).offset().left;

    $(this).animate({
        left: lc,
        top: tc
    });
});

$('.card').focusout(function () {
    $(this).animate({
        top: 0,
        left: 0
    });
});
apaul
  • 16,092
  • 8
  • 47
  • 82
  • Thanks for your elaborate answer. I should have emphasized that I wanted to use transforms, because it would avoid the reflow of the grid. – nambrot May 24 '13 at 07:39
  • yeah, i ended up calculating the offset, but then using that offset to dynamically set the transforms as they are more performant (though not very cross-browser-y) – nambrot May 25 '13 at 23:35
  • @nambrot If its working for you post it as an answer, you may end up helping those that up-voted your question. What cross browser issues are you running into exactly? – apaul May 26 '13 at 00:21