This question already has answers here:
How can I apply multiple transform declarations to one element?
(5 answers)
How to have multiple CSS transitions on an element?
(9 answers)
Closed 2 years ago.
I'm trying to use multiple transforms in a single element so that the end product is a combination of all of the transformations applied together.
However, the only one transform property will be ignored when there are multiple of them.
Say, if I want a div transformed by rotate(20deg) and skewY(20deg), this wouldn't work:
.foo {
transform: rotate(20deg);
}
.bar {
transform: skewY(20deg);
}
<div class="foo bar"></div>
Only one will be applied. Although compounding the transformations could work, it would be impractical as there can be potentially many combinations to the transformations. Rather than doing this:
.one-one {transform: rotate(10deg) skewY(1deg);}
.one-two {transform: rotate(10deg) skewY(2deg);}
.one-three {transform: rotate(10deg) skewY(3deg);}
.one-four {transform: rotate(10deg) skewY(4deg);}
.two-one etc.
I want to do this, so that i can apply the transformations on button clicks, rather than to exhaust all possible combinations of the transformations:
.one {transform: rotate(10deg);}
.two {transform: rotate(20deg);}
.three {transform: rotate(30deg);}
.four {transform: rotate(40deg);}
.uno {transform: skewY(10deg);}
.dos {transform: skewY(20deg);}
.tres {transform: skewY(30deg);}
Current solutions I think are possible:
There is a way to add to the transform property of a <div>
Somehow modify classes in some way
Changing the CSS using jQuery, but it seems like this will also overwrite the property with css() rather than adding to the transform style
I'd prefer css/js solutions, but jQuery answers are welcome too, I'm just not familiar with it.
You may look at CSS var(--X) (see links below snippet's demo) and , set all transformation you intend to 0 by default and update them via the className :(mind support before use : https://caniuse.com/#feat=mdn-css_properties_custom-property_var and eventually a polyfill https://github.com/nuxodin/ie11CustomProperties )
possible exemple without JavaScript https://codepen.io/gc-nomade/pen/RwWLOWr :
.foo {
--rotate: 20deg;
}
.bar {
--skewY: 20deg;
}
div[class] {
transform: rotate( var(--rotate, 0)) skewY( var(--skewY, 0));/* fallback value is here 0 */
}
/* demo purpose */
div[class] {
float: left;
border: solid;
}
html {
display: flex;
height: 100%;
}
body {
margin: auto;
}
<div class="foo bar">foo bar</div>
<div class="foo ">foo</div>
<div class="bar">bar</div>
<div class="nop">no transform</div>
https://developer.mozilla.org/en-US/docs/Web/CSS/--*
Property names that are prefixed with --, like --example-name, represent custom properties that contain a value that can be used in other declarations using the var() function.
Custom properties are scoped to the element(s) they are declared on, and participate in the cascade: the value of such a custom property is that from the declaration decided by the cascading algorithm.
Fallback : https://drafts.csswg.org/css-variables/#example-abd63bac
Note: The syntax of the fallback, like that of custom properties, allows commas. For example, var(--foo, red, blue) defines a fallback of red, blue; that is, anything between the first comma and the end of the function is considered a fallback value.
if supports comes a question, you may look at : IE11 - does a polyfill / script exist for CSS variables?
There's many ways you can approach that. How about this below?
I have created two ` to read the values for skew and rotation and them apply the effects.
Remember it doesn't matter where the values come from. They can be hard-coded in your buttons as data-* attributes(if you want them fixed). This is just to show you how you can approach it with javascript( Ihave added some commends to make it simpler to understand):
var object = document.querySelector(".shape");
// this function takes care of Rotational effect
function rotate(event)
{
var rotation_val = document.getElementById("rotationVal").value;
// this get's the css transform expression for rotation which is
// stored as data-attribute on every button, because it tells you what button is resposible for what transformation. But you can store this anywhere you want.
var css_transform = event.currentTarget.getAttribute("data-rotation");
// this here just replaces say rotate(_r_) to rotate(15deg) if val was 15
var effect = css_transform.replace("_r_",rotation_val + "deg");
// Take not of this. ere I am not overriding the transform property. Instead
// I am adding a transformation to it. more like compounding but dynamically.
object.style.transform += effect;
}
// this function takes care of Skewing effect
function skewY(event)
{
var skew_val = document.getElementById("skewVal").value;
var css_transform = event.currentTarget.getAttribute("data-skew");
var effect = css_transform.replace("_s_",skew_val + "deg");
object.style.transform += effect;
}
function apply_all(){
var buttons = document.querySelectorAll(".effect_button");
buttons.forEach( function(button){
button.click();
});
}
.container{
padding: 60px;
border: thin solid #dbdbdb;
}
.shape{
width: 60px;
height: 60px;
background-color: green;
}
<div class="container">
<div class="shape">
</div>
</div>
<input id="rotationVal" />
<button class="effect_button" data-rotation="rotate(_r_)" onClick="rotate(event)">rotate</button>
<br />
<input id="skewVal" />
<button class="effect_button" data-skew="skewY(_s_)" onClick="skewY(event)">Skew</button>
<br />
Or Rotate and Skew at the same time:
<button onClick="apply_all(event)">Transform</button>
Related
I'm trying to change the opacity of all elements on my document, except for the one I clicked (which has the highest z-Index).
Here is the code I'm using, am I accessing the z-Index's wrongly? When run, the opacity of the whole page changes (including those with a z-Index higher than 6).
allElements = document.getElementsByTagName("*")
for (let i = 0; i < allElements.length; i++) {
if (allElements[i].style.zIndex < 6)
allElements[i].style.opacity='0.7'
}
I would suggest a cleaner and more robust approach based on classes.
Basically use event listeners and toggle classes on your body and your highlightable items. The rest is just CSS as you would imagine.
resetAllHighlights = () => [...document.querySelectorAll('.item')].map(e => e.classList.remove('highlighted'));
toggleHighlightMode = (highlightMode) => {
if (highlightMode) document.querySelector('body').classList.add("highlight-enabled");
else document.querySelector('body').classList.remove("highlight-enabled");
return highlightMode = !highlightMode;
};
[...document.querySelectorAll('.item')].map(e => e.addEventListener('click', (e) => {
resetAllHighlights()
toggleHighlightMode(true)
e.currentTarget.classList.add('highlighted');
}));
.item {
height:100px;
width: 100px;
background-color: red;
margin: 5px;
opacity: 1;
}
body {
display: flex;
}
body.highlight-enabled .item:not(.highlighted) {
opacity: 0.5;
}
<body class="">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</body>
When you access an element's .style property, you will only have access to the styles that were established on the element via the HTML style attribute. If the styling was done via the class attribute or set with JavaScript, the .style property won't be able to access it. In those cases, you must use .getComputedStyle(), which doesn't care how or where the styling was set.
And speaking of how to set styles, it's always better to set styles using pre-made CSS classes and then just add or remove the class(es) as needed instead of setting individual styles. Using classes reduces duplication of code, is easier to manage, and scales better. You can easily access and add, remove or toggle classes with the .classList API.
Also (FYI), don't use .getElementsByTagName() as this is a legacy method that returns a "live node list", which can hurt performance. Instead, use .querySelectorAll()
So, here's an example similar to what you are doing:
let divs = document.querySelectorAll("div.opaque");
// Just set up one event handler at a common ancestor of
// all the elements that may trigger the event
document.addEventListener("click", function(event){
// Check to see if the event was triggered by
// an element you care to handle
if(event.target.classList.contains("opaque")){
// Loop over all the necessary elements
divs.forEach(function(div){
// Check the z-index using .getComputedStyle()
if(getComputedStyle(div).zIndex < 6){
// Instead of modifying a style directly,
// just add a pre-made class
div.classList.add("lightOpaque");
}
});
}
});
body { background-color: red; }
div { height:35px; border:1px dotted grey; position:relative; z-index:5; background-color:skyblue; }
.lightOpaque { opacity: .7; }
.special { position:relative; z-index:7; background-color:aliceblue; }
<div class="opaque">
</div>
<div class="opaque">
</div>
<div class="opaque special">
</div>
<div class="opaque">
</div>
<div class="opaque">
</div>
<div class="opaque">
</div>
This question already has answers here:
CSS scoped custom property ignored when used to calculate variable in outer scope
(2 answers)
Closed 4 years ago.
I have a full working CodePen here showing the problem. I'm using CSS custom properties like so:
:root {
--global-primary-colour-hue: 211;
--global-primary-colour-saturation: 100%;
--global-primary-colour-lightness: 50%;
--global-primary-colour-opacity: 1;
--global-primary-colour: hsla(
var(--global-primary-colour-hue),
var(--global-primary-colour-saturation),
var(--global-primary-colour-lightness),
var(--global-primary-colour-opacity));
}
.box {
background-color: var(--global-primary-colour);
height: 100px;
width: 100px;
}
Then I've set up a range slider and box to display the colour in my HTML:
<input id="hue-range" value="0" type="range" min="0" max="360">
<div class="box"></div>
Finally I want to use the range slider to drive the --global-primary-colour-hue property. I can get this to work like so:
var element = document.getElementById("hue-range");
element.onchange = function(){
document.body.style.setProperty(
"--global-primary-colour-hue",
this.value.toString());
// Why does the box stop changing colour when I comment out this line?
document.body.style.setProperty(
"--global-primary-colour",
"hsla(var(--global-primary-colour-hue),var(--global-primary-colour-saturation),var(--global-primary-colour-lightness),var(--global-primary-colour-opacity))");
}
My question is, why do I have to set the --global-primary-colour property? When I uncomment that last line, the colour in the box no longer changes.
In your script, you're setting the custom properties on the body element. However, in your stylesheet, your custom properties are all (as usual) specified for :root, the html element. So the value of --global-primary-colour-hue is unchanged for :root, and the value of --global-primary-colour in turn remains unchanged. This unchanged value then gets inherited by body and .box — the new value of --global-primary-colour-hue ends up never getting used.
Setting the property for document.documentElement in your script, or changing the CSS rule to target body instead, allows your code to work correctly without needing that last line:
var element = document.getElementById("hue-range");
element.onchange = function(){
document.documentElement.style.setProperty(
"--global-primary-colour-hue",
this.value);
}
:root {
--global-primary-colour-hue: 211;
--global-primary-colour-saturation: 100%;
--global-primary-colour-lightness: 50%;
--global-primary-colour-opacity: 1;
--global-primary-colour: hsla(
var(--global-primary-colour-hue),
var(--global-primary-colour-saturation),
var(--global-primary-colour-lightness),
var(--global-primary-colour-opacity));
}
.box {
background-color: var(--global-primary-colour);
height: 100px;
width: 100px;
}
<input id="hue-range" value="0" type="range" min="0" max="360">
<div class="box"></div>
I am truely sorry if this is a repeated question.
I want to set max-height of #menudd.show to satify my transition. I want to do this in javascript so i can specify the value more precisely.
This is what i got and its not working for some reason...
HTML:
<div id="menudd">
Home
About Me
Short-Term
Middle-Term
Long-Term
</div>
CSS:
#menudd {
position: fixed;
overflow: hidden;
max-height: 0px;
opacity: 0;
width: 200px;
border-radius: 10px;
box-shadow: 0 0 35px 15px black;
transition: all 1s ease;
}
#menudd.show {
opacity: 1;
}
JavaScript:
$("#menudd." + show).get(0).style.maxHeight = document.getElementById("menudd").getElementsByTagName("A")[0].offsetHeight * document.getElementById("menudd").getElementsByTagName("A").length + "px";
This outputs "show is not defined" in the console.
If i use $("#menudd.show").get(0).style.maxHeight it outputs "cannot read property 'style' of undefined" in the console.
If i use $("#menudd.show").style.maxHeight it outputs "cannot read property 'maxHeight' of undefined" in the console.
Any help is highly appreciated! Good day to you. :)
In your question, you said you wanted to look for an element with class "show" inside a div.
You are currently looking for a variable, and not a class. Change this:
$("#menudd." + show)
To this:
$("#menudd.show")
To set the max height, change it to this:
$( "#menuadd.show" ).css( { "maxHeight": document.getElementById("menudd").getElementsByTagName("A")[0].offsetHeight * document.getElementById("menudd").getElementsByTagName("A").length + "px" } );
First, I will add some stuff for readability - like a padding: 0.5em; into you dropdown menu. Also, the <br /> tag after the </a> tags (excluding the last one).
Second, the errors happened because there are no element in the page with the class show. I added it to the <div> of the dropdown to show it working and make the errors go away.
Remember this: if the console says there it is undefined, chances are that either you messed up in how to select the element OR it seriously doesn't exists because you misspelled a letter or let's say you forgot to add a class to a given tag (like in this case).
Third, your code in working condition is available below. It isn't using jQuery easing stuff but pure JavaScript - except by the onclick event that is better to use with jQuery:
$("#menu-dropdown").on("click", function() {
var menu_dropdown = document.getElementById("menudd");
var menu_item = menu_dropdown.getElementsByTagName("A");
$("#menudd").toggleClass("show");
menu_dropdown.style.maxHeight = menu_item[0].offsetHeight * menu_item.length + "px";
} );
#menudd {
padding: 0.5em;
position: fixed;
overflow: hidden;
max-height: 0px;
opacity: 0;
width: 200px;
border-radius: 10px;
box-shadow: 0 0 35px 15px black;
transition: all 1s ease;
}
#menudd.show {
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<span id="menu-dropdown">DropDown</span>
<div id="menudd">
Home<br />
About Me<br />
Short-Term<br />
Middle-Term<br />
Long-Term<br />
</div>
You can view it working also on this video (Youtube) that I recorded.
Fourth, you can add classes, in pure JavaScript, easily. I won't write about it in full since there is a famous question with a godly answer by Peter Boughton already on Stack Overflow. Read it here.
Anyway, to add a class, simply call:
document.getElementById("MyElementID").className += " MyClass";
It is important to note the space. Since it is a string with values, you need to put it otherwise it will treat all the classes as one word (one class) that doesn't exists.
To remove:
document.getElementById("MyElementID").className = document.getElementById("MyElementID").className.replace( /(?:^|\s)MyClass(?!\S)/g , '' );
Explanation available through Peter's answer. So read it there (important)!
Finally, this is out of the scope of the question and merely a reminder: I need to state that if this is a dropdown menu, you will need to add the show class after some focus (or click even) by calling a function in a master menu of some sort and not by hardcoding it into the <div> like I did to show the code working. For example, a "Cars Brand" item of a menu would have a dropdown with the available car brands (Ford, Toyota and etc) after focusing on it.
So, it is wise to transform it in a function that receives the ID of the target dropdown to open. And do not forget to close it after losing focus (or whatever).
This question already has answers here:
Selecting and manipulating CSS pseudo-elements such as ::before and ::after using javascript (or jQuery)
(26 answers)
Closed 3 years ago.
For context, this is a followup to an earlier question. Rather than digging through cssRules, I'd like to base the logic on jQuery selectors that search for the effects of those rules.
Given default properties of
.commentarea .author:before {
background-image: url(http://...);
background-position: -9999px -9999px;
/* ... */
}
that are selectively modified as in
.author[href$="gbacon"]:before /* ... */ {
content: "";
background-position: 0 -140px
}
how can I select pseudo-elements whose respective background positions have default values? Copying the selector as in
GM_log("size = " + $(".commentarea .author:before").size());
matches nothing. Trying .siblings() with
$(".commentarea .author")
.map(function(i) {
GM_log($(this)
.siblings()
.map(function (i) { return $(this).css("background-image") })
.get()
.join(", "))
});
produces only none values.
For full details, see the live page. Is this possible?
You can't use the :before and :after pseudo-elements like this. The purpose of them is to insert content before and after (respectively) the selector you have specified.
Example usage:
HTML:
<span class='a'>
Outer
<span class='b'>
Inner
</span>
</span>
CSS:
.a .b:before {
content: "|Inserted using :before|";
}
.a {
color: blue;
}
.b {
color: red;
}
Result:
http://jsfiddle.net/mzcp6/
What happened was that the text |Inserted using :before| was inserted before (well, really, prepended into) the inner span because it was class b and a descendant of an element of class a. Basically, :before and :after don't select; they modify.
Example:
This doesn't work as expected:
HTML:
<span class='a'>
<p>More text</p>
<span class='b'>
<p>More text</p>
Inner
</span>
</span>
CSS:
.a .b:before {
text-size: 100px;
}
Nothing happens:
http://jsfiddle.net/bQ2ty/
EDIT:
:before is not a valid jQuery selector: http://api.jquery.com/category/selectors/
I think you will need to use something other than :before or attempt to extract the original rule using the jQuery plugin: http://flesler.blogspot.com/2007/11/jqueryrule.html
I have a basic HTML Slider element. What I wish to produce is simple - when the slider is at one end a simple happy face is output. When it is at the other end, a simple sad face is output.
The key thing I want is that there will be a smooth transition from one side of the animation to the other - so the smiley face will go through different phases of indifference and slight happiness/slight sadness.
Let's say there is a float of between 1 and 10 output from the slider, which corresponds to the displayed image's "happiness".
How would you tackle this problem? I have tried searching and googling, but with no good results. All technologies acceptable - particularly interested in how the image/animation would be stored.
You could use CSS's transform: rotateX to do what you'd want. In my version I also used HTML5's input with type="range", but if you wanted to affect old browsers you could use the same approach with a more global slider. The demo involves using two images, one for the face and background and one for the lips, but if you like the technique you can apply it to pure CSS the same way. Just make sure you include all browser prefixes you want in the javascript
Live Demo Here
/* HTML */
<div id='slimey'>
<div id='lips'></div>
</div>
<input id="smileSlide" type="range" onchange="changeSmile(this)" value="0" />
/* Javascript */
var lips = document.getElementById('lips');
function changeSmile(slider) {
var sliderVal = slider.value,
rotateDegree = - sliderVal * 1.8;
lips.style.webkitTransform = "rotateX(" + rotateDegree + "deg)";
lips.style.transform = "rotateX(" + rotateDegree + "deg)";
}
/* CSS */
#slimey {
margin:auto;
background:url(http://i.imgur.com/LGQMhc3.jpg);
background-size: 100% 100%;
height:100px;
width:100px;
position:relative;
}
#lips {
width:50px;
height:20px;
position:absolute;
top:calc(70% - 10px);
left:calc(50% - 25px);
background:url(http://i.imgur.com/20EmUM7.gif);
background-size: 100% 100%;
-webkit-transform:rotateX(0deg);
transform:rotateX(0deg);
}
#smileSlide {
width:100px;
position:absolute;
left:calc(50% - 50px);
}
Inspired by Marco Barria's (this guy has some awesome projects) single element flying bird
If you wanted to make the middle state more visible, you could toggle the display of a line in the middle range like this demo does. Like the rest of this answer it's only an approximate solution, but I think it shows the technique well. If you wanted to get super fancy you could even add a fade in/out for the line to make it appear a tiny bit smoother
I have changed Zeaklous answer by using pure css and js (without any images or rotate)
http://jsfiddle.net/sijav/PVvc4/3/
<!--HTML-->
<div id='slimey'>
<div id='leye' class='eye'></div>
<div id='reye' class='eye'></div>
<div id='lips'></div>
</div>
<input id="smileSlide" type="range" onchange="changeSmile(this)" value="0" />
//Java Script
var lips = document.getElementById('lips');
function changeSmile(slider) {
var lh = lips.style.height, slide=0;
if ((50 - slider.value) > 0){
slide = (50 - slider.value);
lips.style.borderTop = "2px black solid";
lips.style.borderBottom = "none";
}
else {
slide = (slider.value - 50);
lips.style.borderBottom = "2px black solid";
lips.style.borderTop = "none";
}
lips.style.height = slide * 0.4 + "px" ;
lips.style.top = "calc(70% + " + (- slide) * 0.2 + "px" ;
}
/**CSS**/
#leye{
left:25%;
}
#reye{
right:25%;
}
.eye{
position:absolute;
background:black;
border-radius:100%;
height:15px;
width:15px;
top:20px;
}
#slimey {
margin:auto;
background:Yellow;
border-radius:100%;
height:100px;
width:100px;
position:relative;
}
#lips {
width:50px;
height:20px;
position:absolute;
top:calc(70% - 10px);
left:calc(50% - 25px);
background:transparent;
border-top:2px black solid;
-webkit-transform:rotateX(0deg);
border-radius:100%;
transform:rotateX(0deg);
}
#smileSlide {
width:100px;
position:absolute;
left:calc(50% - 50px);
}
EDIT: a small difference in lips moving here http://jsfiddle.net/sijav/PVvc4/4/
For fun, I hacked up a little Webkit-only version in pure CSS (no images or JavaScript) over lunch—here's a demo. I wouldn't necessarily recommend this approach, but I couldn't resist giving it a whirl!
It's a pretty simple approach. Instead of a slider I used a group of radio buttons, which allows you to use the :checked pseudo-class to change the colours and shape of the mouth depending on the selected value. The mouth shape is described using just height and border-radius. For example:
#feel-0:checked ~ #mouth {
border-radius: 30px 30px 0 0;
height: 20px;
margin-top: -5px;
}
The explanatory text is just the label field for the selected radio button. Initially all labels are hidden, but once a field is checked the adjacent label becomes visible:
#happiness input:checked + label {
visibility: visible;
}
You can change which field is selected (visually moving the slider left or right) using your arrow keys—this is built-in behaviour for a radio group.
With a little work, you could adapt this to make the slider look better in non-WebKit browsers; however, it may be janky in some older browsers, and you can't drag the slider left or right. For production I would use a JavaScript slider (e.g. one of the many jQuery options available) and swap the CSS pseudo-class magic for a smattering of JS and a handful of classes.
You could use something like Raphael if you can draw the face in SVG. If you were to keep the same circle face and just morph the mouth for example. This would animate between the shapes. Not quite sure if thats what you mean. This is my 2 second terrible mouth path.
var paper = Raphael( "canvas_container",400,400);
paper.circle(280, 210, 150);
// create the 2 paths to animate between in some app like inkscape
var pathStr1 = "m385,255l-197,-3l40,57l88,1l35,0l34,-55z",
pathStr2 = "m207,268l162,-1l-33,-45l-41,-2l-46,-1l-32,20l-10,29z";
var path = paper.path(pathStr1).attr({fill: "yellow", "stroke-width": 3});
setTimeout(function(){path.animate({path: pathStr2}, 3000, "linear");}, 1000);
There's a fiddle at http://jsfiddle.net/YUhHw/1/ and tutorial with better examples (code above based part on) at http://cancerbero.mbarreneche.com/raphaeltut/#sec-animation and nice examples at http://raphaeljs.com/animation.html I guess you would need to change the setTimeout to correspond to your slider.
Just use a png face without a mouth, and several tween mouths that switch based on the location along the slider with Javascript. Store the files in an array, and call to them from a timed function to check the faces position. Simple and lightweight.
var mouthArray = new Array('frown','half_frown','half_smile','smile');
var face = document.getElementById('face');
var faceLoc = parseInt(face.style.left);
function changeMouth() {
if(faceLoc<10)
{theMouth.setAttribute('src',mouthArray[0]);}
if(faceLoc>10,faceLoc<=19)
{theMouth.setAttribute('src',mouthArray[1]);}
if(faceLoc>20,faceLoc<=29)
{theMouth.setAttribute('src',mouthArray[2]);}
if(faceLoc>30,faceLoc<40)
{theMouth.setAttribute('src',mouthArray[3]);}
}
Something along those lines, if given enough iterations for the length of the slider, should get you a decently 'smooth' effect.