74

I'm trying to achieve something similar to this picture:

enter image description here

I have an image (as part of a slideshow) wrapped in a div, and with :before and :after pseudo-elements, I display two controls to move onto the next (>>) or previous (<<) images of the slideshow.

So far, I have this:

div {
  position: relative;
}

div:before {
  display:block;
  height: 100%;
  content: "stuff";
  position:absolute;
  top: 0; left: 0;
  text-align: center;
}

I can't, however, center the content of the pseudo-elements, the text appears like this:

enter image description here

Is this possible to achieve? If not, what would be the most semantic workaround? I do not want to center the element itself, only its content. I'd prefer to have the element stretched to 100% height.

Edit: http://jsfiddle.net/rdy4u/

Edit2: Also, the img is liquid/fluid, the height of the div/img are unknown, and the width is set to 800px and max-width to 80%.

dcastro
  • 66,540
  • 21
  • 145
  • 155
  • Are you sure that's your code? (see http://jsfiddle.net/RLccx/) – 0b10011 Jan 25 '13 at 14:39
  • 2
    I thought that pseudoelements weren't allowed on empty elements (like img or input...) – Fabrizio Calderan Jan 25 '13 at 14:40
  • `IMG` can't have after and before, anyway he obviously used maybe div. This is just an example. – dfsq Jan 25 '13 at 14:41
  • 2
    @dfsq the devil is in the details. Especially when dealing with more complex layouts, the specifics are important. – 0b10011 Jan 25 '13 at 14:43
  • You are absolutely right, I apologize! I did indeed wrap the img in a div, and applied the pseudo-elements to the div instead. I'm not at home, so I wrote this from what I could remember, I'm sorry. – dcastro Jan 25 '13 at 14:45

6 Answers6

115

Assuming your element is not an <img> (because pseudo elements are not allowed on self-closing elements), let's suppose it's a <div>, so a way could be:

div {
    height: 100px ;
    line-height: 100px;
}
div:before, div:after {
    content: "";
    ...
    display: inline-block;
    vertical-align: middle;
    height: ...;
    line-height: normal;
}

If you cannot change the line-height of the div, another way is:

div {
    position: relative;
}
div:before, div:after {
    position: absolute;
    display: block;
    top: 50%;
    -webkit-transform: translateY(-50%);
    -moz-transform: translateY(-50%);
    -ms-transform: translateY(-50%);
    transform: translateY(-50%);
    content: "";
    width: ...
}

Otherwise, just place the indicators as a background in center position.

dakab
  • 5,379
  • 9
  • 43
  • 67
Fabrizio Calderan
  • 120,726
  • 26
  • 164
  • 177
  • 6
    The first solution is not possible because the height of the div is unknown, and the second isn't possible either because, as I stated, I don't want to center the whole pseudo-element (as you did with `top: 50%`), only its content. – dcastro Jan 25 '13 at 15:01
  • @dcastro your controls `>>` and `<<` are text or they are two images? – Fabrizio Calderan Jan 25 '13 at 15:21
  • I'm just using dummy `lorem ipsum` for now, but I think I'll go with either css or icon fonts to generate the symbols. Almost certainly, I won't use images. – dcastro Jan 25 '13 at 15:25
  • unless, if using images would make this situation possible, I guess I would give it a thought and use images instead. – dcastro Jan 25 '13 at 15:27
  • 1
    using images as background just set the background-position to center – Fabrizio Calderan Jan 25 '13 at 16:03
  • Hmm interesting, I'll try that in a few hours and get back to you. – dcastro Jan 25 '13 at 16:19
46

Using flex in the pseudo element's css it is rather easy:

.parent::after {
  content: "Pseudo child text";
  position: absolute;
  top: 0;
  right: 0;
  width: 30%;
  height: 100%;
  border: 1px solid red;
  display:flex;
  flex-direction:row;
  align-items: center;
  justify-content: center;
}

see https://jsfiddle.net/w408o7cq/

david
  • 662
  • 5
  • 8
9

Using flex box, you should set a fixed width and height in the parent first then

div::after {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}
Alaeddine
  • 1,571
  • 2
  • 22
  • 46
6

I know I'm late for the party but this simple flex solution worked like a charm for me in case it helps any of you.

.main-div {
    display: flex;
    align-items: center;
}

.my-div-name:before, .my-div-name:after {
    /* This content will be vertically centered with the attributes of the main-div */
}
Ken
  • 574
  • 4
  • 15
3

You can do this without resorting to images. (Sometimes you can't, e.g. using font icons inside :before or :after).

div {
   position: relative;
   overflow:hidden;
}

div:before, div:after {
   position: absolute;
   display: block;
   top: 50%;
   -webkit-transform: translateY(-50%);
   -moz-transform: translateY(-50%);
   -ms-transform: translateY(-50%);
   transform: translateY(-50%);

   height:20000px;
   line-height:20000px;

   content: ">>";
}

Admittedly, it's a bit cheeky to use 20000px If your div will ever be larger than that, just increase the px.

In your case, you have an image inside the div, so hit that image with display:block (images don't default to display:block)

Here's the updated fiddle for your particular case. http://jsfiddle.net/rdy4u/56/

galeaspablo
  • 869
  • 5
  • 15
1

Here is a way of creating next and previous controls, using :before and :after pseudo-elements. Along with border trick to create triangles for previous/next buttons. It does not give you an area 100% of height to click, but if you make the triangle (arrows) a big enough size it should make up for that.

div {
  position: relative;
  width: 800px;
  max-width: 80%;
  border: 1px solid red;
  text-align: center;
  margin: 0 auto;
}

div:before, div:after {
  opacity: 0.5;
  display:block;
  content: "";
  position:absolute;
  width: 0; 
  height: 0;
  }

div:before {
  top: 40%; left: 0;
  border-top: 25px solid transparent; 
  border-right: 50px solid blue; 
  border-bottom: 25px solid transparent;
}

div:after {
  top: 40%; right: 0;
  border-top: 25px solid transparent; 
  border-left: 50px solid blue; 
  border-bottom: 25px solid transparent;
}

Here is the code working: http://jsfiddle.net/fiddleriddler/rPPMf/