Vertically centering content of :before/:after pseudo-elements - css

I'm trying to achieve something similar to this picture:
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:
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%.

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.

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/

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;
}

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 */
}

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/

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/

Related

CSS Grid, position absolute an element in a css grid item: IMPOSSIBLE

I have this situation: https://jsfiddle.net/rozkvsdh/5/
A CSS Grid, simply, but in some items, I need to put a ribbon or another div.
It's impossible!
How can I do?
grid-item {
background-color: lightgreen;
display: flex;
justify-content: center;
align-items: center;
}
.ribbon-wrapper {
width: 85px; // the length should be not in px I think!
height: 88px; // the length should be not in px I think!
overflow: hidden;
//position: absolute; it doesn't work!
position: relative;
top: -3px;
left: -3px;
.ribbon {
font: bold 15px sans-serif;
color: #333;
text-align: center;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
position: relative;
padding: 7px 0;
top: 15px;
left: -30px;
width: 120px;
background-color: #ebb134;
color: #fff;
}
}
you could use a pseudo and a data attribute :
HTML5 is designed with extensibility in mind for data that should be associated with a particular element but need not have any defined meaning. data-* attributes allow us to store extra information on standard, semantic HTML elements without other hacks such as non-standard attributes, extra properties on DOM
overflow can be used and background-clip can help to mimic ribbon standing a bit outside
The background-clip CSS property specifies whether an element's background, either the color or image, extends underneath its border.
vmin or vmax units could be used to set font-size to resize the ribbon via em on padding and coordonates.
The viewport-percentage lengths
are relative to the size of the initial containing block. When the height or width of the initial containing block is changed, they are scaled accordingly.
eventually, shadow can be added and linear-gradient can help to draw slanted shadow's parts.
Demo:
body {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
grid-auto-rows: 1fr;
grid-gap: 2px;
height: 100vh;
padding: 5px;
margin: 0;
box-sizing: border-box;
}
grid-item {
background-color: lightgreen;
background-clip: content-box;
display: flex;
justify-content: center;
align-items: center;
position: relative;
overflow: hidden;
padding: 3px;
}
grid-item[data-class="new"]:before {
content: attr(data-class);
position: absolute;
font-size: 2vmax; /* update font-size */
top: 0.4em;
left: -1.3em;
padding: 0em 1.5em;
transform: rotate(315deg);
background-color:gold;
/* eventually add some shadow effects */
background-image:
linear-gradient(135deg, black 0.9em, transparent 1.15em),
linear-gradient(-135deg, black 0.9em, transparent 1.15em);
box-shadow: 0 0 3px;
}
<grid-item>see</grid-item>
<grid-item>full</grid-item>
<grid-item>page</grid-item>
<grid-item>then</grid-item>
<grid-item data-class="new">RESIZE</grid-item>
<grid-item>window</grid-item>
<grid-item>to</grid-item>
<grid-item>see</grid-item>
<grid-item>ribbon</grid-item>
<grid-item data-class="new">font&size</grid-item>
<grid-item>updates</grid-item>
<grid-item>F</grid-item>
<grid-item data-class="new">PRO</grid-item>
<grid-item>B</grid-item>
<grid-item>C</grid-item>
<grid-item>D</grid-item>
<grid-item>E</grid-item>
<grid-item>F</grid-item>
<grid-item>A</grid-item>
<grid-item>B</grid-item>
you need to put position: relative; on grid-item and then you can use absolute position on .ribbon-wrapper.
grid-item {
background-color: lightgreen;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.ribbon-wrapper {
width: 85px; // the length should be not in px I think!
height: 88px; // the length should be not in px I think!
overflow: hidden;
position: absolute;
top: -3px;
left: -3px;
.ribbon {
font: bold 15px sans-serif;
color: #333;
text-align: center;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
position: relative;
padding: 7px 0;
top: 15px;
left: -30px;
width: 120px;
background-color: #ebb134;
color: #fff;
}
}
https://jsfiddle.net/thesouthstar86/rozkvsdh/6/
You can do it and also works for resize but it's a bit messy.
The spacer divs are there so you have the height. You need one on each side because you want PRO to be centered. We sacrifice 1px on each side to make this work and now ribbon-wrapper can be absolute
https://jsfiddle.net/rozkvsdh/9/
HTML
<grid-item>
<div class="ribbon-wrapper"><div class="ribbon">NEW</div></div>
<div class="spacer"></div>
<div>PRO</div>
<div class="spacer"></div>
</grid-item>
CSS
// this is new
.spacer {
height: 88px;
width: 1px;
}
grid-item {
background-color: lightgreen;
display: flex;
justify-content: center;
align-items: center;
position: relative; // added
}
.ribbon-wrapper {
width: 85px; // the length should be not in px I think!
height: 88px; // the length should be not in px I think!
overflow: hidden;
position: absolute;
top: 0; // edited
left: 0; // edited
}
The ribbon won't align left because it's an in-flow child of a flex container with justify-content: center. So both the ribbon and the content are centered side-by-side.
You can override that setting with margin-right: auto, which will left-align the ribbon, but it will also right-align the content.
You can insert an invisible spacer item to create equal balance in the container, keeping the content centered. But that's a bit involved and may be unnecessary.
Stick with CSS positioning properties. This will position the ribbon. Re-sizing it is another matter:
grid-item {
background-color: lightgreen;
display: flex;
justify-content: center;
align-items: center;
position: relative; /* establish nearest positioned ancestor for abspos containment */
}
.ribbon-wrapper {
overflow: hidden;
position: absolute;
top: 0;
left: 0;
bottom: 0;
}
.ribbon-wrapper .ribbon {
font: bold 15px sans-serif;
color: #333;
text-align: center;
transform: rotate(-45deg);
position: relative;
padding: 7px 0;
top: 15px;
left: -30px;
width: 15vw;
background-color: #ebb134;
color: #fff;
}
revised fiddle

Align to left side of contaner a element rotated -90deg

div {
width: 300px;
height: 300px;
border:1px solid black;
}
h1 {
width: 300px;
transform: rotate(-90deg)
}
<div>
<h1>Hola</h1>
</div>
If you try this snippet, you will see that the h1 is rotated and placed in the center of the div (makes sense, they have same width)
But how to align it to the left? (flexible container's width)
You can position the h1 element absolutely with respect to the parent div and then use transform-origin property to specify the axis about which the rotation should happen.
In the below snippet, the element is positioned at the bottom of the parent and because the origin is set at left-bottom, the left-bottom of the element (h1) stays at its position during rotation.
Now because of the rotation, the element would go outside of the parent after rotation. To bring it back into position add translateY(100%) to the transform stack. A text-align: right is added to set the content at left-top. The text-align makes it look a bit more hackish than it actually is but otherwise it is difficult to position at left-top.
div {
position: relative;
width: 300px;
height: 300px;
border: 1px solid black;
}
h1 {
position: absolute;
display: inline-block;
bottom: 0px;
width: 300px;
text-align: right;
transform: rotate(-90deg) translateY(100%);
border: 1px solid;
transform-origin: left bottom;
}
div, h1 {
margin: 0px;
padding: 0px;
}
<div>
<h1>Hola</h1>
</div>
Note to future visitors: Unlike using static values for positioning, this solution using translateY() would be able to adapt itself automatically even if the length of the content increases or spans multiple lines like in the below snippet. Again, the only drawback would be that the text would be right aligned.
div {
position: relative;
display: inline-block;
width: 250px;
height: 250px;
border: 1px solid black;
}
h1 {
position: absolute;
display: inline-block;
bottom: 0px;
width: 250px;
text-align: right;
transform: rotate(-90deg) translateY(100%);
border: 1px solid;
transform-origin: left bottom;
}
div,
h1 {
margin: 0px;
padding: 0px;
}
<div>
<h1>Halooo</h1>
</div>
<div>
<h1>Some lengthy content which wraps around</h1>
</div>
check this out it will give a direction to your required solution..
div {
width: 300px;
height: 300px;
border: 1px solid black;
}
h1 {
width: 70px;
margin-left: -20px;
float: left;
transform: rotate(-90deg)
}
<div>
<h1>Hola</h1>
</div>
Updated
Or you can do in this way also
div {
width: 300px;
height: 300px;
border: 1px solid black;
}
h1 {
position: absolute;
left: -10px;
top: 2px;
transform: rotate(-90deg)
}
<div>
<h1>Hola</h1>
</div>

Align text on top, right, bottom and left of image?

I'm trying to add text on all four sides of image but i cant get the right text to align properly. The right text is still on left side.
FIDDLE: https://jsfiddle.net/y75L0ww9/
<span class="top">Text on top</span>
<span class="left">Text on left side</span>
<img src="http://www.uaa.alaska.edu/web/images/horizontal-large.jpg" />
<span class="right">Text on right side</span>
<span class="bottom">Text on bottom</span>
img {
max-width: 100%;
height: auto;
border: 0px none;
vertical-align: middle;
display:block;
margin:0 auto;
}
.top, .bottom {
display: block;
text-align: center;
margin-left: auto;
margin-right: auto;
overflow: hidden;
}
.left {
display: inline-block;
background-color: #FF0;
transform: rotate(-90deg);
position: relative;
top: 200px;
left: 0px;
}
.right {
display: inline-block;
background-color: #F00;
transform: rotate(90deg);
position: relative;
right: 0px;
bottom: 200px;
}
You should add wrapper around Your image (for now it can be body), ad give it position: relative; Then modify .right class:
.right {
display: inline-block;
background-color: #F00;
transform: rotate(90deg) translate(0, -50%);
position: absolute;
right: 0px;
top: 50%;
}
updated fiddle
(btw. in wider viewport the left text is also not so nicely layed out right now ;) )
You will have to wrap all those 5 elements into another element, e.g.:
.wrapper {
display: inline-block;
position: relative;
}
Having this, you'll be able to easily align your spans inside by giving them position: absolute.
use position: absolute; instead of position: relative;
Updated fiddle

How to style a rectangular div with elliptical rounded sides?

How to style a rectangular div with elliptical rounded sides?
You can get an ellipse by setting border-radius 50%.
You can get two elements, one inside the other, with different sizes, and so get the 2 ellipses needed
.test {
position: absolute;
left: 40px;
top: 40px;
width: 200px;
height: 200px;
border-radius: 50%;
overflow: hidden;
}
.test:after {
content: "";
position: absolute;
left: -30%;
top: 10%;
width: 160%;
height: 80%;
background-color: lightblue;
border-radius: 50%;
}
In this case, using an pseudo element , and so, only one div is needed
demo
Have you checked out this website? Try this:
div
{
border:2px solid;
border-radius:25px;
}

Trapezium span with CSS

Is there any way I could draw a trapezium span thing with text in it? Doesn't matter if the corners are rounded, in fact, I'd prefer it if they were. I know how to make an oval/circle with border-radius, but I'm stuck on the trapezium. Help please!
I did it pure css using pseudo-elements and skew css property with support border-radius: demo on dabblet.com
http://img135.imageshack.us/img135/9683/eedea21cb3bc438fb33c80c.png
html: <span>Trapezium</span>
css:
span {
display: block;
z-index: 1;
position: relative;
/* custom sizes */
width: 200px;
height: 50px;
}
span:before,
span:after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
bottom: 0;
z-index: -1;
}
span:before {
transform: skew(25deg);
left: 25px;
}
span:after {
transform: skew(-25deg);
right: 25px;
left: auto;
}
UPD: demo without pseudo-elements
Use this css code
span {display:block;
border-bottom: 100px solid red;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
height: 0;
width: 100px;
}
I did it once, think it was something like this:
http://jsbin.com/ebejip/

Resources