How to use skew only in the parent element? - css

Is there any way to use skew only in a parent element?
I need to create something like a 'diamond' as a mask and the child elements can't be affected. There is no way, in this case, to use png as a mask.
Thanks in advance!

It's really easy, you just need to unskew the thing for the children. Unskew means applying another skew transform, but of opposite angle this time.
.parent { transform: skewX(45deg); }
.parent > * { transform: skew(-45deg); }
In general, if you apply a number of transforms on a parent element and you want the child elements to go back to normal, then you have to apply the same transforms, only in reverse order (the order does matter in most cases!) and with a minus for angle/ length values used for skew, rotate or translate. In the case of scale, you need a scale factor of 1/scale_factor_for_parent. That is, for scale, you would do something like this:
.parent { transform: scale(4); }
.parent > * { transform: scale(.25); /* 1/4 = .25 */ }
A diamond shape with children is pretty easy.
DEMO
Result:
HTML:
<div class='wrapper'>
<div class='diamond'>
<div class='child'>Yogi Bear</div>
<div class='child'>Boo Boo</div>
</div>
</div>
CSS:
.wrapper {
overflow: hidden;
margin: 0 auto;
width: 10em; height: 10em;
}
.diamond {
box-sizing: border-box;
margin: 0 auto;
padding: 4em 1em 0;
width: 86.6%; height: 100%;
transform: translateY(-37.5%) rotate(30deg) skewY(30deg);
background: lightblue;
}
.child {
transform: skewY(-30deg) rotate(-30deg);
}

Any transform property affects the element which is applied to and all of his children.
So the only way to skew a single "parent" element is to have it with no children (i.e.: it can't be also a parent!).

Could ou try to elaborate a bit on what do you want to get as a result ?
skew(), like all transform properties always affects the child elements. You could try to use two HTML blocks at the same position, one with the skew() and the other with the contents.
Also, if you just want a diamond, a rectangular box with scale() and rotate() should be enough, but again with no children.
And if you want that diamond as a mask, I'm pretty sure it would be easier to render the parts NOT present in the diamond. Rendering the outside parts of the diamond should not be that hard, after all, they're only rectangle triangles.

the only way to achieve this is to take the child element out of the document flow using position:absolute; and putting an equal negative degree skew on the child.
The problem with this is that you will now have to resize your parent manually.

Related

CSS: "overflow: hidden" alternative that doesn't break 3D transforms

I'm trying to make a horizontal section with a parallax effect. In the background there should be an image that scrolls at a different speed than the page.
The problem is: I want the parallax element to be contained in the parent element, so the parent element works kind of like a mask for the child: the child is only visible within the boundries of the parent.
I know that this can be achieved by having the parallax element beetween two elements with backgrounds that are "above" the parallax element and obstruct it, but this method is not applicable for my case.
The obvious idea that comes to mind is to use overflow: hidden on the parent. This however breaks the 3D transforms so there is no parallax left.
How do I achieve the described effect?
Here is a codepen: https://codepen.io/rradarr/full/mdwgard.
I want the red rectangle to not be visible outside the "parallax-container" with the black border.
* {
margin: 0;
}
html, body {
height: 100%
}
main {
position: relative;
width: 100%;
perspective: 1px;
transform-style: preserve-3d;
overflow-y: auto;
overflow-x: hidden;
height: 100vh;
background-color: blue;
}
.static {
min-height: 800px;
}
.parallax-container {
border: solid black 3px;
height: 600px;
width: 100%;
transform-style: preserve-3d;
position: relative;
}
.parallax-child {
position: relative;
width: 100%;
height: 100%;
transform: translateZ(-2px) scale(2.01);
z-index: -1;
}
#img-or-whatever {
height: 900px;
width: 100%;
background-color: red;
position: relative;
z-index: -1;
}
<main>
<div class="static"></div>
<div class="parallax-container">
<div class="parallax-child">
<div id="img-or-whatever"></div>
</div>
</div>
<div class="static"></div>
</main>
As far as I know you can't achieve the described effect with translateZ.
This is because according to this article about CSS 3D
...giving overflow any value other than visible effectively forces the value of transform-style to flat, even when we have explicitly set it to preserve-3d.
The only alternative for overflow hidden is to put something "above" the parallax element as far as I know (which you said you want to avoid).
If there is really no option to put something "above" the parallax element you could try to do something similar with js (something like this for example). This is not ideal since it will imply a lot of calculations and variables and might take some time to accomplish exactly what you want (and you loose the 3D inside the container since you need overflow: hidden anyway).
If you really need the 3d inside there you could create a more complex solution with javascript that skips overflow: hidden as well. But I'd try to avoid that if is not mandatory (I'd rather add an absolute element over the overflow: hidden container where 3D is enabled. And give the absolute container transparent background if you still need 3D in that section).
Usually I would also advise to try to avoid .js for this kind of stuff (if possible) but I don't think you have a lot of options here.
You could try the :not() pseudo clss, but I don't know what you would pass into the parentheses that would be similar to not in the black square.

Simulating transform-origin using translate

I want to simulate the properties of transform-origin using transform: translate in CSS.
According to MDN, this is very possible:
This property is applied by first translating the element by the negated value of the property, then applying the element's transform, then translating by the property value.
However, when I try, I get incorrect results. These two rectangles are clearly not the same:
.origin {
transform-origin: 100px 100px;
transform: translate(100px, 0px) scale(2) rotate(45deg);
}
.translate {
transform: translate(-100px, -100px) translate(100px, 0px) scale(2) rotate(45deg) translate(100px, 100px);
}
.box {
background-color: red;
width: 100px;
height: 100px;
}
.container {
float: left;
margin: 100px;
width: 250px;
height: 250px;
background-color: rgba(0, 0, 0, 0.1);
}
<div class="container">
<div class="box origin">
</div>
</div>
<div class="container">
<div class="box translate">
</div>
</div>
I have tried looking for the answer without luck for quite some time now, and in my mind it should be relatively simple, I just can't figure it out.
You are almost good but you have two errors. You need to invert the translations and you need to change the transform-origin of the second one.
If you check the documentation, you will see that the reference used to translate the origin is the top left corner of the element and the default value of transform origin is center. So we need to have the same reference for both.
.origin {
transform-origin: 50px 50px;
transform: rotate(45deg) scale(2);
}
.translate {
transform-origin:0 0;
transform:translate(50px, 50px) rotate(45deg) scale(2) translate(-50px, -50px);
}
.box {
background-color: red;
width: 50px;
height: 50px;
}
.container {
display: inline-block;
margin: 30px;
width: 150px;
height: 150px;
background-color: rgba(0,0,0,0.1);
}
<div class="container">
<div class="box origin">
</div>
</div>
<div class="container">
<div class="box translate">
</div>
</div>
Here is from the specification:
The transformation matrix is computed from the transform and
transform-origin properties as follows:
Start with the identity matrix.
Translate by the computed X and Y of transform-origin
Multiply by each of the transform functions in transform property from
left to right
Translate by the negated computed X and Y values of transform-origin
You need to pay attention to the wording! You may find that the MDN is contradictory with the specification BUT it's not the case simply because there is a difference between translating the element (like described in the MDN) and translating the origin of the element or the local coordinate (like described in the specification).
For example, translating the element by -50px is equivalent to translating its local coordinate (origin) by +50px.
You need to also pay attention to the "Multiply from left to right" as it may create confusion. If we refer to the same specification in the Example 3 we have:
div {
height: 100px; width: 100px;
transform: translate(80px, 80px) scale(1.5, 1.5) rotate(45deg);
}
This transformation translates the local coordinate system by 80
pixels in both the X and Y directions, then applies a 150% scale, then
a 45° clockwise rotation about the Z axis. The impact on the
rendering of the element can be intepreted as an application of these
transforms in reverse order: the elements is rotated, then scaled,
then translated.
So multiplying from left to right doesn't mean applying from left to right which somehow explain the need of inverting the translation you applied to simulate the transform-origin:
transform-origin can not be that easy simulated using transform: translate. Using transform-origin you change center of transformations, so rotations and all other transforms are calculated based on different point.
Take a look on below example from MDN with transform-origin: 50px,50px. Rotated element is below bottom edge of dotted square by value unable to calculated easily. You could, for sure, simulated transform-origin with transform: translate by values would need to be calculated for particular combination of values.

css transform translate - move to another element position

Given 2 elements on a web page, how can i animate one elements position so that it moves to the second element, which can be anywhere on the page.
Transform translate doesnt seem to work well as i would need to know the difference in the position of offset between the two elements.
Is there any pure css way to achieve this?
very similar to the animation on adding a product to the shopping cart on this page: https://www.triwa.com/en-gb/watches/family/current-collection/ivory-falken-steel-mesh/
You could do this sort of thing with transition. so the changing of the elements position is transitioned over 1 second or however long you want.
Example: 2 boxes, Box1 and Box2. On clicking box 2 we want it to shrink and move to box 1
HTML:
DEMO: https://jsfiddle.net/33m3t16d/1/
Hope this helps mate.
$('.box2').click(function() {
$(this).removeClass('box2');
$(this).addClass('box1');
});
.container {
position: relative;
}
.box {
background: #333;
border: 1px solid #fff
}
.box1 {
transition: all 1s;
position: absolute;
top: 0px;
left: 500px;
height: 20px;
width: 20px;
}
.box2 {
position: absolute;
top: 100px;
left: 0px;
height: 100px;
width: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="container">
<div class="box box1"></div>
<div class="box box2"></div>
</div>
Nope, there is not. You can't retrieve element positions of a random positioned element. You need to involve JS if you do not know the target position.
One approach would be, to read the target positions from the target element via JS and write a short CSS snippet into the page containing the transition rules. This way you may use JS to read and set the necessary position. But the animation itself is still rendered through the browser itself (while being defined in CSS).
I don't think there is a pure CSS way to calculate the x distance and y distance between 2 elements. You have to use JS for this. Calculate the distance between 2 elements in JS and translate the required element to the 2nd element using .css function
As others have said, theres no pure CSS way. however here is a jquery option that you can either use with the onclick="moveToElementPosition(this,'#target');" attribute
Or
$('#box2').click(function(){
moveToElementPosition('#elementToMove','#target');
});
This function will get the postion and size of the target and move your element to match. The speed it does it is dictated by the transition:all 1s;
Here's a demo: https://jsfiddle.net/33m3t16d/3/

Align Top of Background with Bottom of Element with CSS

I want to align the top of a background image with the bottom of an element using CSS (so that I can make it transition in upon hover or in an animation, in case you were wondering). This element does not have a set height; I don't know what the height of the element is. Does anybody know how to do this? The solution does not have to be IE compatible; it only has to work in the latest versions of Chrome and Firefox.
EDIT: I'll award the bounty to an answer that also works for the <body> element if there is such an answer by the time that the bounty ends.
Sorry about the trouble. Gotta love CSS right? Anyhow I have two solutions for you: One just stays within the realms of using background positioning and achieves it... for the MOST part; The other one goes outside of the immediate solution, adds just a little bit extra, but is rock solid and works with any height at all. Both work with any width.
So the first one:
This works by setting the background-position to the keyword value center for the xpos and the percentage value 1000% for the ypos. Of course the % value can vary, but I just went with 1000% to be safe. In reality you could make this just big enough to push it off screen. But here's the fiddle:
http://jsfiddle.net/D5QME/
The problem with this one is that if you make the height of the parent element the exact height of the background image... it quits working. And if the height of the parent element shrinks below the height of the image, it reverse the pattern. So if you're confident that the parent element will always be taller than the BG image, this is pretty solid.
Now the second one:
This one is straight up rock solid but adds an extra element. This extra element can either be a placeholder element, like a div or whatever, or just the straight img itself. This:
1) Uses position: relative and overflow: hidden on the parent to turn it into a container
2) Uses position: relative, margin: 0 auto, and top: 100% to position the image in the center and push it just below the parent
3) and uses .parent:hover .backgroundImage to make the image transition to top: 0% when the user hovers over the parent element.
Here's the fiddle:
http://jsfiddle.net/Fwf6p/
Even though this adds an extra element, it is pretty rock solid.
Anyhow, hope this helps!
-J Cole Morrison
Another modification of J Cole's answer, but seems to work with the body tag. May also work with Hephistocles modification but haven't tested that.
CSS:
.example{
border: 1px solid red;
/* Change the height to anything you want! */
height: 400px;
/* Change the width to anything you want! */
width: 500px;
position: relative;
}
.example:hover .backgroundImage{
height: inherit;
top: 0%;
}
.backgroundImage{
background: url("http://img.gadgetian.com/Angry-Birds-Space-021-300x300.png") no-repeat top center;
position:relative;
margin: 0 auto;
top: 100%;
-webkit-transition: 1s ease all;
-moz-transition: 1s ease all;
transition: 1s ease all;
height: 0px;
}
HTML:
<body class="example">
<div class="backgroundImage"></div>
</body>
JSFiddle
To take J Cole's second answer a bit further - if you want to avoid inserting an extra element you could always use pseudo-elements. For example:
.myElm {
position: relative;
overflow: hidden;
}
.myElm:after{
content:"";
background: url("myimage.png") no-repeat top left;
top:100%;
position: absolute;
}
.myElm:hover:after {
top:0;
}
If you know the height of your element in pixels, you may be able to set its background position to be: background-position:0 npx;. Not sure otherwise. If there's a maximum height, you could always just use that. Or have a reasonable estimate/limit. The transitions may not 'ease' very uniformly, however.
There was an excellent JSFiddle in another answer just now, but it's been deleted :(

Is Opacity is INHERITED in a div

Is it possible to remove the opacity inheritance from a parent to it's child div?
Example
<style type="text/css">
.parent {
opacity:.5;
}
.parent div {
opacity:1; /* I want this to override the ".5", but instead it combines */
}
</style>
<div class="parent"><div></div></div>
Like fmsf says, it's not possible.
If you're looking for a way to make background-color or color transparent, you could try rgba. This is not supported in IE6.
#my_element {
/* ie6 fallback - no opacity */
background-color:rgb(255, 255, 255);
/* rgba(red, green, blue, alpha); */
background-color:rgba(255,255,255,0.5);
}
No, not strictly in the sense you're inquiring about. Because what's happening is not really that the value is inherited in any traditional sense, but the child control is part transparent as a direct effect of being within a partly transparent container.
You can work around it, tho, in a lot of situations.
So this won't work:
<div id="parent" style="opacity: 0.5; background-color: red;">
<div id="child" style="opacity: 1"> Still just 50% visible </div>
</div>
But you could do something like this:
<div id="wrapper" style="position: relative;">
<div id="parent" style="position: absolute; top: 0; left: 0; opacity: 0.5; background-color: red; width: 100%;"> </div>
<div id="child" style="position: absolute; top: 0; left: 0;"> This will be 100% visible </div>
</div>
There are a handful of caveats, but this is the only good way to achieve what you want.
In this example I'm dealing with one line of text, and in the "parent" I'm including an which will also occupy one line in height. If your "child" is of a greater height, the "parent" will not grow, because it is really not a parent at all. You'll have to manually set a height.
You'll also manually have to specify width, as you're dealing with absolutely positioned elements.
I'll say, tho, before people start saying that absolute positioning is such a terrible way to solve design problems, that there is one occasion where I think it is perfectly legit: when also dealing with position: relative as in the above example, and to absolutely position an element based on that, and not on the entire window.
No you can't
Opacity is completly inherited from the fathers div.
meaning:
#father{
opacity: 0.5;
}
#child{
opacity: 0.9; /* actualy means opacity 0.5*0.9 == 0.45 of opacity value */
}
Edit:
If you want to cheat it but retaining the "workflow" of your transparent father. You can put a copy (in size and position) of the father div, on top of the father.
#father, #copy{
your css here
opacity: 0.5;
}
#copy{
opacity: 1;
background: transparent;
z-index: 1000; /* or one more than the father */
}
Now instead of putting your non transparent HTML on the father, put it on the copy.
Create a transparent PNG and apply it as the background of the parent class instead of using opacity.
For a demo, see Twitter's layout (specifically the background/border around the main content).
You can avoid the parent-child opacity inheritance but it will be hacky:
http://www.impressivewebs.com/css-opacity-that-doesnt-affect-child-elements/
There is also a plugin to do the job, called: thatsNotYoChild.js.
With HTML5 you can also use RGBA to set a background color whose transparency (alpha) is not inherited.
Example:
/* Black with 75% transparency */
background-color: rgba(0, 0, 0, 0.25);

Resources