I was reading this, it says
#keyframes rules don't cascade, so animations never derive keyframes
from more than one rule set.
what does "cascade" mean here? English is not my native language and there is no more detailed explanation so I don't understand what it means. Can anyone explain this with an example?
An example of CSS cascading: -
h1 {
font-size: 12px;
width: 200px; /* Sets width */
}
h1 {
font-size: 14px; /* Overrides 12px rule above */
height: 200px; /* Sets height */
}
In the above example the h1 elements font size is first set to 12px in the first rule and then overridden to be 14px by the second rule. The width is set in the first rule and the height is set in the second rule. This is cascading: multiple rules determine the final styles applied, with priority given to properties in the rules descending order.
An example of Keyframes cascading
/* WILL NOT CASCADE */
#keyframes exampleAnimation {
0% { top: 0; left: 0; margin: 10px; }
100% { top: 100px; margin: 20px; }
}
#keyframes exampleAnimation {
0% { top: 0; left: 0; }
100% { top: 0; left: 100px; }
}
The above example will not cascade. That is to say, only the last rule declaration is used for the animation. The animation will move the animating element 100px to the left, it will ignore the top and margin animations set in the previous rule declaration.
Related
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;
}
It seems a bit counter intuitive to have properties, which on their own are key:value pairs, be grouped together. Especially since most of them are quite different and can still be used simultaneously as long as you know how to write it. In case it's not clear what I'm talking about, my question is this. Why is the following:
transform: rotate(40deg) scaleX(1,5) translate(-10px, 20px);
Not written like so:
rotation: 40deg;
scaleX: 1.5;
translate: -10px 20px;
This way each property can be manipulated on their own, without having to keep track of the sibling values. There must be a good reason the W3 choose this approach, so does anyone know it?
That's because transforms are not commutative. Therefore, the order matters.
For example, if you use a translation after a rotation, the translation direction will be rotated too.
.first::after {
transform: rotate(180deg) translateX(50px);
}
.second::after {
transform: translateX(50px) rotate(180deg);
}
body {
display: flex;
flex-direction: space-around;
}
div {
height: 100px;
width: 100px;
border: 5px solid;
margin: 25px auto;
}
div::after {
content: 'Hello';
display: block;
height: 100%;
width: 100%;
background: yellow;
opacity: .5;
}
.first::after {
transform: rotate(180deg) translateX(50px);
}
.second::after {
transform: translateX(50px) rotate(180deg);
}
<div class="first"></div>
<div class="second"></div>
With different CSS properties, you couldn't choose the order you want. That's the limitation of CSS Transforms level 2 that BoltClock mentioned, the spec defines an order and you can't alter it.
The CSS transform property originated from SVG transforms, where a space-delimited list of transform functions is provided as a value for the SVG transform attribute. The CSS transform property is most likely a direct port of that.
Of course, hindsight has shown this to be a terrible mistake, and the transform functions will be promoted to their own CSS properties in CSS Transforms level 2, with almost the exact syntax that you have proposed (there aren't individual scaleX/Y/Z properties yet). Their interaction with the transform property is accounted for, although the draft notes that the transformation matrix will be changed to accommodate how the new properties will interact with respect to the cascade.
I agree that the option with individual would be nice, as you for example would be able to manipulate them with ease with Javascript. The probable reason that this isn't the case is that the order of the declarations matter with transform. The axes on which the element moves change when you rotate the element etc.
/* Transform */
.translate {
transform: translateX(200px) rotateZ(90deg);
}
.rotate {
transform: rotateZ(90deg) translateX(200px);
}
/* Demo */
div {
width: 100px;
height: 100px;
background-color: red;
margin-bottom: 10px;
position: relative;
}
div.translate:before {
position: absolute;
display: block;
content: '';
width: 100px;
height: 200px;
top: 100px;
left: 0;
border:2px dashed #333;
border-top:none;
box-sizing:border-box;
}
div.rotate:before {
position: absolute;
display: block;
content: '';
width: 200px;
height: 100px;
top: 0;
left: -200px;
border:2px dashed #333;
border-right:none;
box-sizing:border-box;
}
<div class="translate">
</div>
<div class="rotate">
</div>
The spec for keyframe animations says that !important will be ignored in keyframes -- it's invalid if set inline in the animation declaration.
From the example spec:
#keyframes important1 {
from { margin-top: 50px; }
50% { margin-top: 150px !important; } /* ignored */
to { margin-top: 100px; }
}
#keyframes important2 {
from { margin-top: 50px;
margin-bottom: 100px; }
to { margin-top: 150px !important; /* ignored */
margin-bottom: 50px; }
}
Is there a known workaround to this?
There are really only two options:
Rewrite the CSS code to avoid the use of !important
Use JavaScript animations instead of CSS animations. A JavaScript solution would be able to alter any inline styles or even document-level stylesheets if necessary
I have few classes:
.overlay-blue {background-color: rgba(0,123,238,0.9);}
.overlay-orange { background-color:rgba(240,116,7,0.9); }
.overlay-purple { background-color:rgba(126,64,228,0.9); }
.overlay-green { background-color:rgba(57,151,95,0.9) }
.overlay-pink { background-color:rgba(173,33,106,0.9); }
.overlay-light-blue {background-color:rgba(0,183,168,0.9) }
.overlay-red {background-color:rgba(235,50,89,0.9); }
.overlay:hover
{
-webkit-animation-duration: 0.5s;
-webkit-animation-name: fadeInFromNone;
background-color: rgba(0,0,0,0.3);
}
#-webkit-keyframes fadeInFromNone {
0% {display:block; background-color: rgba(0,0,0,0.9);}
1% {display: block ; background-color: rgba(0,0,0,0.89);}
100% {display: none ; background-color: rgba(0,0,0,0.3);}
}
`
this function of hovering is working well but it turns the overlay to black when starging the animation because of the line
0% {display:block; background-color: rgba(0,0,0,0.9);}
which makes sense.
is there a way to dim the alpha channel without duplicating the code for each color?
There is no easy way going about your current approach, because it is impossible to target just the alpha channel in the rgba() property separately and change it. What you can do, however, is instead of setting a background colour on your element, set the background colour of a pseudo-element stretched to the full dimension of its parent, and only declare the rgb() values. The alpha channel changes can be delegated to the opacity property instead. I call this the pseudo-element approach:
Pseudo-element approach
/* Define BG colours of pseudo element instead */
.overlay-blue::before { background-color: rgb(0,123,238);}
.overlay-orange::before { background-color:rgb(240,116,7); }
/* and more... */
/* Set relative positioning of parent element */
.overlay {
position: relative;
}
/* Stretch pseudo element, declare empty content so it will show */
.overlay::before {
content: '';
opacity: .9;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
transition: all .5s ease-in-out;
z-index: -1;
}
/* Change opacity when parent element is hovered upon */
.overlay:hover::before {
opacity: 0.3;
}
Of course this is a rather basic implementation of your question (see demo fiddle here), because I do not know the exact details you want to achieve with your animation keyframes. The good thing is that pseudo-elements can also be animated :)
SASS approach
Even better: Alternatively, you might want to consider using a CSS preprocessor (SCSS, LESS) so that you can use variables, and do not have to repetitively redeclare the background colours. See the demo here.
You can use the following mixin:
/* Declare mixin */
#mixin overlayColor($color) {
background-color: rgba($color, 0.9);
&:hover { background-color: rgba($color, 0.3); }
}
/* Use #include for each colour class, you only have to declare the rgb(a) values */
.overlay {
margin-bottom: 10px;
padding: 20px;
position: relative;
transition: all .5s ease-in-out;
&.overlay-blue {
#include overlayColor(rgb(0,123,238));
}
&.overlay-orange {
#include overlayColor(rgb(240,116,7));
}
/* and more... */
}
I'm kinda new to LESS, so I'm not sure if that's possible and how.
So my idea is this :
I have a main-stylesheet.less and a dozen smaller stylesheets each of which contains several versions of styling for a particular element i.e. header.less, footer.less, main-nav.less etc.
So in header.less every variant of styling is linked to a condition and when you include this LESS file in the main-stylesheet.less via this condition, just that particular chunk of code is compiled and not the other ones that are linked to other conditions.
I hope I've been thorough enough for you to best understand me.
Is this possible and how ?
Keeping it Generic
By using conditional mixins, the code in main-stylesheet.less stays generic, with only the variables changing to control what is actually compiled.
Example header.less
.header() when (#header = 1) {
#header {
your: properties;
for: header1;
}
}
.header() when (#header = 2) {
#header {
your: properties;
for: header2;
}
}
This could continue on, and similar code would be in the other footer.less files, etc.
Example main-sytlesheet.less
#import header.less;
#import main-nav.less;
#import footer.less;
/* set your variables for your conditional mixins */
#header: 1;
#main-nav: 3;
#footer: 3;
/* call the mixins */
.header();
.main-nav();
.footer();
The global variables you set will only choose the .header() mixin to generate the #header, etc. that #header variable is set to.
I think maybe your looking for a LESS mixin?
/* header.less */
.header1 () {
// including selector
.header {
position: relative;
z-index: 1001;
width: 100%;
margin: 0 0 20px;
overflow: hidden;
}
}
.header2 () {
position: relative;
z-index: 1001;
width: 50%;
margin: 20px;
}
.header3 () {
position: relative;
z-index: 1;
width: 90%;
margin: 0 0 50px;
overflow: hidden;
}
And include it like this:
/* main-stylesheet.less */
#import 'header.less';
body {
.header1();
}
You could also get smart and use one mixin:
.header (#margin: 0, #width: 100%) {
position: relative;
z-index: 1001;
width: #width;
margin: #margin;
overflow: hidden;
}
header {
.header(0 0 20px, 50%);
}