First time really using the pseudo :after selector. Not sure if the problem I'm running into is a limitation of it or I'm just missing something obvious.
Here's my live code.
li.current:after {
border-width: 1px 1px 0 0;
content: ' ';
background: #256f9e;
display: block;
height: 13px;
position: absolute;
width: 10px;
top: 6;
margin:0px auto;
z-index: 99;
transform: rotate(-224deg);
-webkit-transform: rotate(-224deg);
-moz-transform: rotate(-224deg);
-ms-transform: rotate(-224deg);
-o-transform: rotate(-224deg);
transform-origin: 50% 50%;
-webkit-transform-origin: 50% 50%;
-moz-transform-origin: 50% 50%;
-ms-transform-origin: 50% 50%;
-o-transform-origin: 50% 50%;
text-align: center;
float: center;
}
I've created a little triangle (Or rather a box that has been rotated to look like a triangle). I want it centered within the <li></li> but can't figure it out using my normal methods.
The things that have failed (in no particular order):
text-align: center;
float: center;
margin: 0 auto;
margin-right: 0;
margin-left: 0;
What am I missing? I doubt it matters, but I'm using AngularJS. Thought I'd mention it in case there is a known conflict between Angular & Pseudo selectors (which I doubt).
Thanks.
The issue is your use of absolute positioning & the method you're using to try and center it. If you position an element absolutely, the ol' margin: 0 auto; method won't work to center the thing. I point you to an explanation as to why this is at the end of the question, but in case you just want this to work let's get to the solution first.
Here's some working code. View it on JSFiddle
#tool-menu li {
...
position: relative;
}
li.current:after {
...
position: absolute;
width: 10px;
top: 6;
left: 50%;
margin-left: -5px;
}
Let's break down what's going on here.
Setting up a new Containing Block
In your original Fiddle, the pseudoelement is positioned absolutely relative to the viewport. An example might be the best way to show what this means, and why we don't want this. Consider setting it to top: 0. This would keep it latched to the top of the browser window (or, in this case, the JSFiddle frame), rather than the parent (the li). So, if our menu happened to be at the bottom of the page, or even moving around, the pseudoelement would be floating independent from it, stuck to the top of the page.
This is the default behavior of an absolutely positioned element when you don't explicitly set the position on any parent elements. What we want is to have its position defined relative to the parent. If we do this then the pseudoelement sticks with the parent, no matter where it happens to be.
To make this happen, you need to set the parent, #tool-menu li, to be explicitly positioned (which means setting it to be anything other than position: static). If you choose to use position: relative;, it won't change the computed location of the parent on the page, and does the thing we want. So that's why I used that one.
In technical terms, what we're doing here is creating a new containing block for the child.
Positioning the Pseudoelement
Now that our absolute positioning will be determined in relation to the parent, we can take advantage of the fact that we can use percentages to define where to place the child. In this case, you want it centered, so I set it be left: 50%.
If you do just this, though, you'll see that this lines up the left edge of the pseudoelement at 50%. This isn't what we want – we want the center of the pseudoelement to be at the middle. And that's why I added the negative margin-left. This scoots it over a bit to line the middle up with the center of the parent.
And once we do that, it's centered! Brilliance!
Why didn't my margin: auto; work?
The auto value of a margin is calculated from a fairly complex algorithm. At times, it computes to 0. I know from experience that this is one such instance of that happening, though I haven't yet traced my way through the algorithm to see exactly why. If you'd like to run through it, take a look at the spec most browsers have most likely implemented.
Using calc to center
You can also use the calc function in css to center the pseudo element.
Note: This isn't supported in IE8 and below (caniuse) but you can provide a fallback for older browsers.
View it on this code pen. I'm also using MarkP's css border method to draw the triangle.
li.current:after {
content: '';
display: block;
height: 0;
position: absolute;
width: 0;
overflow: hidden;
bottom: -5px;
left: calc(50% - 5px);
z-index: 2;
border-top: 5px #256f9e solid;
border-left: 5px transparent solid;
border-right: 5px transparent solid;
}
Wouldn't be better to just define the width as a percentage, make it a block element and text-align it in the center?
"float: center;" is invalid, and won't work. Mixing floated and absolute positioned elements are a sure way to get trouble with your layout as they don't really work that well togheter.
Try something like this:
li.current:after {
content: 'YOUR CONTENT';
display: block;
width: 100%;
text-align: center; }
Using margin:auto to center
As long as the element has a width declared you can use the absolute centering method.
To use this method the right and left properties must be set to 0 for margin: auto to be effective.
This method can be expanded to implement horizontal centering as well.
see link for full info:
http://www.smashingmagazine.com/2013/08/09/absolute-horizontal-vertical-centering-css/
li.current:after {
content: "";
position: absolute;
display: block;
right: 0;
bottom: -5px;
left: 0;
margin: auto;
border-width: 5px;
border-style: solid;
border-color: transparent;
border-top-color: #256f9e;
width: 200px;
height: 200px;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
}
<div>
<ul>
<li class="current"></li>
</ul>
</div>
Not directly related (have already voted up jmeas) but you may also find it easier to use the CSS border trick to make the triangle. e.g.
li.current:after {
content: '';
display: block;
height: 0;
position: absolute;
width: 0;
overflow:hidden;
bottom: 0;
left: 50%;
margin: 0 0 -5px -5px;
z-index: 99;
border-top: 5px #256f9e solid;
border-left: 5px transparent solid;
border-right: 5px transparent solid;
}
Similar tactics as to what jmeas has suggested with regards to the vertical positioning. We align to the bottom and then use a negative margin-bottom to push this out to the desired location.
With transform: translate() centering can be accomplished without a fixed size. This is because translate(<x>%) will use the (psuedo-)element's own size, while left and margin-left will use the container's size. By using these together we can therefore find the exact center-point.
tl;dr
To center vertically:
.container {
position: relative;
}
.container:after {
top: 50%;
transform: translateY(-50%);
}
To center horizontally:
.container {
position: relative;
}
.container:after {
left: 50%;
transform: translateX(-50%);
}
Full example
.container {
position: relative;
display: inline-block;
background: #4aa;
color: white;
padding: .5ex 1ex;
}
.container:after {
content: ":after";
position: absolute;
background: #a4a;
color: white;
padding: .5ex 1ex;
/* position below container */
top: 100%;
/* move right by 50% of containers width */
left: 50%;
/* move left by 50% of own width */
transform: translateX(-50%);
}
<p class="container">
Container with content
</p>
This may be the simplest way to do it:
.child_class::after{
position: absolute;
content: 'YourContentHere';
width: 100%;
text-align: center;
top: 50%;
}
the simplest way to do this -
With pesudo element :after or :before use display: inline-block;
Try something like this:
content: url(../images/no-result.png);
display: inline-block;
width: 100%;
text-align: center;
Using display: grid to center ::before
...worked nice for me. I'm using fa-Icons on this page and centered them within an element with 50% border-radius:
i {
font-size: 0.9rem;
border: 1px solid white;
border-radius: 50%;
width: 30px;
aspect-ratio: 1;
margin-inline: 5px;
}
i::before {
width: 100%;
height: 100%;
display: grid;
place-items: center;
}
This tutorial can help you to make center CSS pseudo-elements.
https://techidem.com/centering-pseudo-before-after-elements-content/
h2 {
text-align: center;
color: #181818;
padding-bottom: 20px;
margin-bottom: 35px;
border-bottom: 1px solid #eaeaea;
position: relative;
}
h2::after {
content: "";
width: 70px;
height: 4px;
background-color: #ff0000;
left: calc( 100% - ( 50% + 35px ) );
position: absolute;
display: block;
bottom: 0;
}
<h2>Most Recent Posts</h2>
You may use container queries with grid layout
element {
container-type: size;
&::after {
content: '';
position: absolute;
width: 100cqw;
height: 100cqh;
display: grid;
place-items: center;
}
}
Container queries: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries
I personally don't really like the idea to change position attribute or do some margin manipulation. I think the easiest way is two lines of CSS:
.element::after {
/* your css */
line-height: initial;
vertical-align: initial;
}
And there is no need to touch the parent.
Related
I want to have some list elements that got a dynamically adjusting height via css.
For better understanding: I am inserting via ::before a number that I count via counter-increment (thats the big ones)
Problem is that nothing that I tried so far brings me even close to what i want to archive. If you change the window size everything gets shoven down...
It should look like this:
I tried:
clear: both; on every element (except the li)
height: auto; on every element
I've already read through some posts but nothing really worked for me.
Dont ask why am I trying to get it done with css... ;)
Thanks for any help!
You have an absolute positioning on your image and thumbnail wrapper which is causing huge problems, look at the adjusted CSS below:
.page-id-3606 .product_thumbnail_wrapper .product_thumbnail a img {
position: relative;
clear: both;
}
.page-id-3606 .product_thumbnail a::before {
counter-increment: section;
content: "0" counter(section) "";
font-size: 10em;
font-weight: bold;
position: relative;
/* top: 100px; */
/* left: 50%; */
line-height: 0;
height: 100px;
width: 100%;
text-align: center !important;
box-sizing: border-box !important;
text-transform: uppercase;
color: #464646;
display: block !important;
border-bottom: 3px solid #464646;
/* transform: translate(-50%, 0); */
margin: 0 !important;
z-index: 10 !important;
}
I fixed it with a little help from Rich.
the missing height and top was causing the trouble:
.page-id-3606 .product_thumbnail_wrapper::before {
content:'';
background: url('...');
height: 130% !important;
width: 100%;
position: absolute;
z-index: 1;
clear: both;
top: -65px;
}
I'm trying to make a odd-shaped dialogue box shaped liked one in the link below (without the wiggly tail). I've thought about doing it through polyfill, but that ended up making the element too large. I thought I could maybe do it with pseudo elements, but I didn't think I could put a shadow behind effect and have the odd-shaped top/bottom with just two pseudo elements.
The best method I could think of was to nest multiple divs inside the main one and position them with absolute and set the top manually, but I was wondering if there was an easier way of doing so.
If I want to make a div like this and write things inside without them being cut off, how should I go about doing it?
A single element with pseudo classes absolutely positioned using perspective and transforms can look like that.
div {
position: relative;
display: inline-block;
color: white;
margin: 3em;
perspective: 250px;
}
div::before, div::after {
content: '';
position: absolute;
z-index: -1;
top: -1em;
left: -1.5em;
right: -2em;
bottom: -1em;
background: black;
padding: 2em 3em .5em .5em;
transform: rotateX(180deg) rotateY(15deg) rotate(1.5deg) skewX(25deg);
}
div::before {
background: white;
top: -1.5em;
left: -2.25em;
right: -2.75em;
bottom: -1.75em;
transform: rotateX(180deg) rotateY(15deg) skewX(35deg);
}
body {
background: red;
}
<div>i know kung foo</div>
Can I achieve a custom CSS border with a button at one end which looks like this
Without url(some image link)?
Note: I want so because when I want to change color, I have to manipulate image.
I have achieved using image JS Fiddle
#stretch {
border-image: url(http://akitech.org/img/border.png) 30 30 stretch;
}
The easiest way is to use CSS pseudo-elements to create the decoration (the circle at the left) and to mask the chamfer at the right of the border (the angle at which the border-right would otherwise meet):
div {
border: 10px solid transparent;
width: 250px;
padding: 10px 20px;
position: relative;
/* this property has to be set to change the border-color: */
border-bottom-color: #f90;
}
/* common shared styles: */
div::before,
div::after {
/* to ensure the pseudo-elements are rendered: */
content: '';
/* for positioning: */
position: absolute;
/* positioning the element with its uppermost edge
against the bottom of the element, against the
upper side of the bottom-border: */
top: 100%;
/* again, set to change the color of the ends: */
background-color: #f90;
}
div::before {
/* position against the left edge: */
left: 0;
/* move the pseudo element 10px up, and
10px left: */
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
/* making the pseudo-element a circle: */
border-radius: 50%;
}
/* masking the chamfer of the border-bottom's
right-most edge: */
div::after {
left: 100%;
/* making the height/width the same width
as the border itself: */
height: 10px;
width: 10px;
}
div {
border: 10px solid transparent;
width: 250px;
padding: 10px 20px;
position: relative;
border-bottom-color: #f90;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div id="stretch">Here, the image is stretched to fill the area.</div>
In order to have these borders adapt to the length of the text, either the elements you want to have custom-bordered must themselves be able to contract to the width of the text, either using float:
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
/* forces the element to take up only that space required by
its (non-floated) contents: */
float: left;
/* forces the floated elements to the next line: */
clear: left;
}
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
float: left;
clear: left;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div>text</div>
<div>longer text</div>
<div>much longer text</div>
<div>much much much longer text</div>
Or, possibly more simply, use display: inline-block:
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline-block;
}
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline-block;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div>text</div>
<div>longer text</div>
<div>much longer text</div>
<div>much much much longer text</div>
Or display: inline (these don't automatically force new-lines between elements, obviously):
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline;
}
div {
border: 10px solid transparent;
position: relative;
border-bottom-color: #f90;
padding-left: 20px;
display: inline;
}
div::before,
div::after {
content: '';
position: absolute;
top: 100%;
background-color: #f90;
}
div::before {
left: 0;
margin: -10px 0 0 -10px;
height: 30px;
width: 30px;
border-radius: 50%;
}
div::after {
left: 100%;
height: 10px;
width: 10px;
}
<div>text</div>
<div>longer text</div>
<div>much longer text</div>
<div>much much much longer text</div>
summary:
for simplist way to this question, should not using svg, pure css can draw the shape author expected very well cause it's a combination of cycle(border radius)+rect(thicker line), let's refer to the David's answer should be the easiest and most clean way to draw that shape under text.
//below is my debugging history and tries (i searched out many ways to approach it);
//though not good answers
I use background css attribute (not OP wanted) Op used border-image also valid.
<div class="custom-border" >SOME TEXT HERE</div>
<style>
.custom-border{
padding-left:20px;
width:200px;
background:url(http://img1.wikia.nocookie.net/__cb20140224040010/shantae/images/b/bc/HGH_border_bottom.png) 0px 5px no-repeat;
background-size:contain;
height:150px;
}
</style>
later I realized OP might dislike using image traditional way, I re understand the
question is asking how to draw that shape in pure css and place it under the text and the responsive should be as flexible as the traditional way the svg shape will auto strech with the text placed on it.
after that, I've find some way to generate svg and place under text
see if it works for no image solution or you can get it improved based on fiddle
http://jsfiddle.net/hahatey/hsfxS/1464/
during the process, i've found this useful tool of generating svg from below reference url: http://svg-edit.googlecode.com/svn/branches/2.6/editor/svg-editor.html
But the flaw is it's still a fixed width solution, the line svg won't auto stretch.
Have found a unclean way to improve auto stretch though not in pure css responsive way.
but auto strech can be done by dynamically change below line
<rect stroke="#ff0000" id="svg_2" height="8" width="100%" y="27" x="40" stroke-width="5" fill="#FF0000"/>
where width="100%" or fixed value => width="function return value"; //
// during this try, i found a little bug, jquery seems unable to select svg or element inside svg? however svg element tag attribute can be written in backend languge so still valid.
//3.44
Another way without touching the inner "rect' element below "svg" tag, is to add a container to the whole thing, and using function to dynamically
assign width for the container;
like my attempt in this
fiddle: http://jsfiddle.net/hahatey/hsfxS/1468/
so at least the width can be dynamically calculated out by a function to calculate the text length of the upper text so the line will be able to strech if the calculation is accurate enough. There could be other ways to do svg auto strech with the text using pure css if other ppl find it.
Thanks.
5.02// since the author didn't say how complex the content is inside the container,
I've created a demo in pure css triggered effct --- auto strech the shape along with the text above it in below fiddle. but i said it sure has many limitations though looks similar.
http://jsfiddle.net/hahatey/a9z1kyx7/
my upper fiddle is only able to align correctly for singleline auto strech
I'm wondering if complex content (more than one line, there maybe a lot of block,inline mixed tag element inside which increases complexity for alignment) can also use css to do such decoration width auto adjustment without touching javascript or backend language.
Due to browser performance implications I can't use box-shadow CSS property because I have many similarly looking elements on my page that should have same looking style including shadow. That's the reason I would like to implement shadows using traditional PNG imagery.
Facts
My elements have predefined and more importantly fixed pixel width
They have fluid height (auto) depending on their content
They have content directly in the element and some child elements will be positioned outside their border
CSS3 can be used but performance-critical parts (gradients, shadows...) should be avoided
CSS pseudo elements can be used without limitation
Requirements
There should be no additional wrapper element added in order to have fluid shadow
Application should run smoothly on mobile browsers - shadows seem to slow down performance significantly on mobile devices since their processing power is much lower than desktop computers.
Possible direction
I thought of using :before and :after pseudos to display top-to-bottom and bottom shadows on the containing element, but these pseudos display within their parent element and positioning parent z-index higher than these children has no effect.
Visual demo of end result
This JSFiddle Demo in pure CSS3 that I would like to achieve but using PNG shadows. In reality there are numerous of these boxes so you can imagine mobile browsers are struggling with all these shadows.
Item is one such box (see blow) that needs PNG shadow. Left menu is child element positioned outside of the box.
Display in Chrome
HTML
<div class="item">
<menu>
<li>Yes</li>
<li>No</li>
<li>Maybe</li>
</menu>
<div class="content">
Some content
</div>
</div>
CSS3 LESS
.item {
position: relative;
width: 300px;
background-color: #fff;
box-shadow: 0 0 10px #ccc;
margin: 20px 20px 20px calc(20px + 3.5em);
min-height: 5em;
&:first-child {
margin-top: 0;
}
&:after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 10px;
height: 5em;
background-color: #fff;
}
menu {
position: absolute;
top: 0;
left: -3.5em;
width: 3.5em;
margin: 0;
border: 0;
padding: 0;
list-style: none;
background-color: #fff;
box-shadow: 0 0 10px #ccc;
li a {
display: block;
text-align: center;
padding: 2px 0;
}
}
.content {
padding: .75em 1em;
}
}
Probably I am missing something, but looks like you want something in this way:
demo
The CSS is
.base {
width: 300px;
height: 150px;
font-size: 100px;
font-weight: bolder;
background-color: lightgreen;
position: relative;
z-index: auto;
}
.base:after {
content: '';
position: absolute;
top: 30px;
left: 30px;
background-color: green;
z-index: -1;
width: 100%;
height: 100%;
}
.child {
position: absolute;
left: 150px;
top: 50px;
border: solid 1px black;
color: red;
}
And just change the background of the :after to your image.
I have applied this solution to your fiddle.
The relevant CSS is for the before pseudo element:
.item:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
z-index: -1;
background-image: url(http://placekitten.com/100/100);
background-repeat: no-repeat;
background-size: 100% 100%;
}
I have used a kitten picture, that is being scaled to cover all the needed size. Just change that to whatever you want.
I needed to do it that way because I had onky a pseudo element available.
The key for that to work (and where you probably had the difficulty) is to add z-index: auto to .item
Updated demo
Well, I had said that it wasn't posible, but I have find a way.
The standard technique would be to use 2 elements, just to avoid stretching the image (as you said). The problem is that we only have 1 pseudo element available.
The solution then would be to use 1 pseudo element, but with 2 backgrounds, to solve the issue.
CSS (only relevant part)
.item:before {
background-image: url(http://placekitten.com/320/10), url(http://placekitten.com/320/500);
background-repeat: no-repeat;
background-size: 100% 9px, 100% calc(100% - 9px);
background-position: left bottom, left top;
}
We will need an image (the first one) only 10 px in height, to cover the bottom shadow. And another one, with enough height to cover the maximumitem posible, and that will be used for the remaining part of the shadow. The dark part is that we need now a calc() height, with limited support. (anyway, better than border image)
demo 3
In this simplified example I have 4 circles, each with varying border-width and I am trying to maintain equal line height in each to keep them horizontally aligned.
However the border width seems to effect the line height (despite being technically outside the box?)
Is there anyway to solve this without manually adjusting each line-height?
width: 50px;
height: 50px;
border-radius: 50px;
border: 1px solid #1daeec;
line-height: 50px;
Example: http://jsfiddle.net/vcJ3G/
You can remove the line-height, use display:table-cell instead, and add vertical-align:middle; to your stat class.
jsFiddle example
.stat {
display: table-cell;
width: 50px;
height: 50px;
border-radius: 50px;
border: 1px solid #1daeec;
text-align: center;
margin: 10px;
font-size: 16px;
color: #1daeec;
text-transform: uppercase;
vertical-align:middle;
}
Your css works fine all you have to do is remove some from top section
* {
margin: 0px;
padding: 0px;
}
http://jsfiddle.net/techsin/vcJ3G/15/
Came across this and thought myself how is it possible to do it without using table-cell, my solution probably not the best, but I just decide to share it anyway.
http://codepen.io/svdovichenko/pen/rObzqM?editors=110
adding <span>1</span> (can use class inside spam didn't use for this example)
.stat{
position: relative;
}
and
span {
position: absolute;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
}