I want to create a horizontal line similar to the one found on this post and marked as the solution but only with the shadow appearing at the bottom.
The closest I can get is getting the shadow shown in the middle of the line, both up and down.
Like this?
.fancy-line {
border: 0;
height: 1px;
position: relative;
margin: 0.5em 0;
}
.fancy-line:before {
top: -0.5em;
height: 1em;
}
.fancy-line:after {
height: 0.5em;
top: calc(-0.5em + 1px); /* adjusted this */
}
.fancy-line:before, .fancy-line:after {
content: '';
position: absolute;
width: 100%;
}
.fancy-line, .fancy-line:before {
background: radial-gradient(ellipse at center, rgba(0,0,0,0.1) 0%, rgba(0,0,0,0) 75%);
}
body, .fancy-line:after {
background: #f4f4f4;
}
-Some Text-
<div class="fancy-line"></div>
The original code generates a radial gradient and covers the bottom half of it with a block colored the same as the background. Adjusting it to your requirements is just a matter of moving the covering piece from the bottom to the top.
Also, note: hr elements are required to be self closing. This precludes the use of :before and :after since self-closing elements can't have children. In the referenced answer, they weren't using any particular feature of hr, so I've converted it to a div here.
Take a look at this: http://jsfiddle.net/9rovqvoj/1/
It's basically the same, but adding a mask before pseudo element :before instead of :after and added a z-index to it.
hr.fancy-line:after {
top: -0.5em;
height: 1em;
}
hr.fancy-line:before {
content: '';
height: 0.5em;
top: -0.5em;
z-index: 999;
}
Related
This question already has answers here:
Thick underline behind text
(7 answers)
Closed 8 months ago.
I am trying to use a background color on text only, which works fine on single lines, but when the line breaks in responsive mode it ends up looking like this:
Does anyone know what to add to make the yellow background line follow the text on mulitple lines?
This is my code:
.background-highlight {
position: relative;
display: inline-block;
color: #faf9f4;
}
.background-highlight:after {
content: '';
position: absolute;
width: 100%;
height: 10px;
left: 0;
top: 50%;
background-color: #cef230;
z-index: -1;
}
Thanks a lot in advance,
I have used box-decoration-break: clone; property for mainting the same design for multiple lines don't forget to add display: inline; to its child where background is added. in child I have used linear gradient you can generate according to you from here. you can chenge the position of green strip by adjusting gradient values from the site.
.background-highlight {
position: relative;
display: inline-block;
color: #000;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
font-size: 120px;
}
.background-highlight span {
display: inline;
background: rgb(206,242,48);
background: -webkit-gradient(linear, left bottom, left top, color-stop(11%, rgba(206,242,48,1)), color-stop(12%, rgba(255,255,255,0)));
background: -o-linear-gradient(bottom, rgba(206,242,48,1) 11%, rgba(255,255,255,0) 12%);
background: linear-gradient(0deg, rgba(206,242,48,1) 11%, rgba(255,255,255,0) 12%);
}
<h1 class="background-highlight"><span>The skippers escape</span></h1>
It is fault of pseudo element that is forced to break between two lines.
The cause is the way the effect is carried out, pseudo element ::before creates a single rectangle that has no way of splitting up to follow words flow. Posible solutions:
Make sure links never occupy more than 1 line. You can use
white-space: nowrap;
Redesign the effect applying box border to main element. For example:
.background-highlight {
width: max-content;
border-bottom:5px solid rgb(217, 255, 0);
}
<div class="background-highlight">THE SKIPPER´S ESCAPE</div>
Pseudo-element solution
Use the bottom-positioning value on the pseudo-element instead of top. This forces the pseudo-element to be positioned at the bottom, instead of 50%from the top. I used bottom: -10px as that is the height of the pseudo-element, so it aligns perfectly.
Read more on position values: https://developer.mozilla.org/en-US/docs/Web/CSS/position
HTML-element solution
Instead of creating a pseudo-element, you could opt to make an HTML element instead.
Make a parent container, apply flex to it so the text and the line will align.
Make the .line-element a block element, so it will break into a new line.
You can still apply position: absolute and position: relative on the .line and the h2 if you want to position it in another way. Or you could simply use e.g. transform: translateY(5px) to move the line up a bit.
.background-highlight {
position: relative;
display: inline-block;
color: black;
text-align: right;
}
.background-highlight:after {
content: '';
position: absolute;
width: 100%;
height: 10px;
left: 0;
bottom: -10px;
background-color: #cef230;
z-index: -1;
}
/* Without pseudo */
.nopseudo {
display: flex;
}
.nopseudo h2 {
text-align: right;
}
.nopseudo .line {
height: 10px;
width: 100%;
background-color: #cef230;
display: block;
}
<h2 class="background-highlight">The Skippers <br>Escape</h2>
<div class="nopseudo">
<h2>The Skippers <br>Escape<span class="line"></span></h2>
</div>
I don't know how is your structure but this might help.
We just need two div elements, one as a container to setup the width property and the text holder in this case I will use a h2 tag.
Just mkae the ::after pseudo element as display and the .background-highlight's width can be width: match-content or 100% in this case if you just want to cover the text use match-content if you want to cover the width of the .title element use 100%
.title {
width: 90vw;
text-align: end;
}
h2 {
text-transform: uppercase;
color: #374650;
}
.fullwidth {
width: 100%;
}
.match {
width: match-content;
}
.background-highlight {
position: relative;
display: inline-block;
}
.background-highlight:after {
content: '';
display: block;
width: 100%;
height: 10px;
background-color: #cef230;
z-index: -1;
}
<div class="title">
<h2 class="match background-highlight">
The Skipper's <br>Escape</h2>
</div>
<div class="title">
<h2 class="fullwidth background-highlight">
The Skipper's <br>Escape</h2>
</div>
I'm trying to put a dot in each corner of a container. I'm thinking the trick to this is a combination of .my-container:before and setting the :before's border or background property. The effect I want is similar to SO#17306087, but I don't want to use images.
Edit
jsfiddle
I'll be using this quite a bit, so would prefer it to happen automatically with a css class (not require additional DOM elements).
Edit
Since svg is text-based and can be inserted directly into css, I'm looking into that method. I see here that this does work: example fiddle
my updated fiddle (currently has a css error that I'm trying to pin-point) fixed fiddle with 4 dots using background prop
The svg is valid and not throwing errors as DOM: fiddle
You can do it only on a div and with standard CSS.
The trick is to use the pseudo elements to display 2 circles using radial gradients.
.test1 {
width: 200px;
height: 200px;
background-color: lightblue;
position: absolute;
left: 220px;
}
.test1:before, .test1:after {
content: "";
position: absolute;
height: 100%;
width: 20px;
top: 0px;
background-image: radial-gradient(circle at center, red 5px, transparent 5px), radial-gradient(circle at center, red 5px, transparent 5px);
background-size: 20px 20px;
background-position: top center, bottom center;
background-repeat: no-repeat;
}
.test1:before {
left: 0px;
}
.test1:after {
right: 0px;
}
fiddle
You could also draw the circles in the elements itself, but then you can not apply it to elements having background.
The above code renders the circles pixelated. It's better leaving 1 pixel for the red/transparent transition
background-image: radial-gradient(circle at center, red 5px, transparent 6px), radial-gradient(circle at center, red 5px, transparent 6px);
updated fiddle
Assuming you're okay with something a little crazy, there is a CSS only solution that's completely based on a single class (on a single element). The only caveat is that that element MUST have at least one child element (which should probably be the case anyways, right?)
.my-container:before, .my-container:after, .my-container *:first-child:before, .my-container *:first-child:after {
content: '';
height: 5px;
width: 5px;
position: absolute;
background: #777;
border-radius: 50%;
}
.my-container:after {
right: 0;
top: 0;
}
.my-container *:first-child:before {
left: 0;
bottom: 0;
}
.my-container *:first-child:after {
bottom: 0;
right: 0;
}
You can use :before and :after to create your dots, though the challenge comes in the fact that this only creates two dots per element. Because of this, I've set it to look for the first element inside the container, and apply the same styles to that. (the wildcard selector * looks for any element, and :first-child makes sure it only gets applied to one child element)
See fiddle:
http://jsfiddle.net/5N9ep/2/
Now obviously this won't work in every situation, and you can always mess with the selector for that second element if you have something that will work better.
Other than that, if you want to make it a little more practical (but less cool), I would recommend just making two wrapper div elements, and giving each one of them a unique class, each creating two dots with a simple :before and :after.
http://jsfiddle.net/qQP84/
HTML :
<div class="maindiv">
<div class="lefttop dot"></div>
<div class="leftbottom dot"></div>
<div class="righttop dot"></div>
<div class="rightbottom dot"></div>
</div>
CSS
.maindiv {
height: 150px;
width: 150px;
background: blue;
position: relative;
}
.dot {
height: 12px;
width: 12px;
border-radius: 100%;
background: red;
position: absolute;
}
.lefttop {
top: 0;
left: 0;
}
.leftbottom {
bottom: 0;
left: 0;
}
.righttop {
right: 0;
top: 0;
}
.rightbottom {
right: 0;
bottom: 0;
}
EDIT:
jQuery solution to easily append the dots to different divs that have the same class
$('<div class="lefttop dot"></div><div class="righttop dot"></div><div class = "leftbottom dot"></div><div class="rightbottom"></div>.appendTo('.myDivsThatNeedDotsClass');
This will append(give) the 4 dots to each element that has the class .myDivsThatNeedDotsClass
With this approach you can remove the HTML from above, but keep the css like it is.
If you don't have the same class for all of them, than you can do this
.appendTo('.myDivsThatNeedDotsClass, .anotherClassThatNeedsDots, #anIDthatNeedsDots');
the following can be your mark-up
<div class="my-container">
<div class="tr"></div>
<div class="tl"></div>
<div class="br"></div>
<div class="bl"></div>
<p class="stuff">Some stuff</p>
</div>
the css as follows
body {
margin: 10px; /* for visibility */
}
.my-container {
background-color: #eee; /* for visibility */
position: relative;
width:98%;
border:1px dotted red;
}
.my-container .stuff {
text-align:center;
}
.tr,.tl,.br,.bl{
position:absolute;
border:5px solid red;
border-radius:10px;
}
.tr{
top:0;
right:0;
}
.tl{
top:0;
left:0;
}
.br{
bottom:0;
right:0;
}
.bl{
bottom:0;
left:0;
}
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
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.
I have used html and body attributes to have a gradient background and a flower background for my website.
I have also used a div to have the bottom right hand flower where it is. Works great, but not when scrolling. How do i get the bottom right hand corner image to stick to the bottom of the screen ?
You will want to set position: fixed; instead of position: absolute;.
Here's more info on the Position Property.
.bottomright {
position: fixed;
bottom: 0px;
right: 0px;
}
.demo {
background-color: HotPink;
padding: 20px;
margin: 5px;
}
Hello<br>
<div class="demo bottomright">
I'm a Div!
</div>
there
if you put the flower inside a div and position it absolute bottom and right this will stick it there.
For example, something like this will work
#mystylename{
position:absolute;
bottom:0;
right:0;
}
you may need to tweak it to get it sat where you want and also maybe add a z-index
If you require animation, set you div as absolute before the animation and then after the animation re set it to fixed as the below example.
$('.mydiv').animate({
opacity: 1,
right: "50px",
bottom: "50px",
height: "toggle"
}, 1000, function() {
// Animation complete.
}).css('position','fixed');
css for the above div is below as well.
.mydiv {
text-align: center;
background: #00DD88;
background: -moz-linear-gradient(center top , #00DD88 0%, #00CC00 100%) repeat scroll 0 0 transparent;
border-radius: 30px 30px 30px 30px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
margin: 5px 0 10px 15px;
position: absolute;
right: -980px;
width: 200px;
height: 50px;
display: none;
z-index: 100;
}
I know this is old but it will definitely help someone :)
A css-only trick for this old post is to put a after the div and position the top -1.2em so it overlaps the bottom of the element above it.
html:
<textarea class="no-whitespace-right">This is a test resize it.</textarea>
<span class="float-lower-left">length could go here</span>
css:
.no-whitespace-right {
/* any whitespace to the right and the overlap trick fails */
width: 100%;
}
.float-lower-left {
position: relative;
float: right;
right: 1em;
top: -1.2em;
/* push it up into the element before it. This is a trick for bottom-right */
right: 1em;
z-index: 200;
opacity: 0.5;
font-weight:bolder;
}
https://jsfiddle.net/qwm3pu8d/
You might need to use JavaScript to accomplish this task. Such techniques will accomplish the effect you desire, but they tend not be animate very smoothly. When scrolling, such a "stuck" object will tend to skip and stutter. I found an example here but have not tried it myself. I recommend searching for a few examples and trying out the one that looks cleanest and most modern.
You will want to set position: fixed; instead of position: absolute;