Combining multiple "transform" entries in Less - css

I have two mixins which both convert to -webkit-transform:
.rotate(#deg) {
-webkit-transform: rotate(#deg);
}
.scale(#factor) {
-webkit-transform: scale(#factor);
}
When I use them together:
div {
.rotate(15deg);
.scale(2);
}
... they (as expected) show up as:
div {
-webkit-transform: rotate(15deg);
-webkit-transform: scale(2);
}
This doesn't seem to be valid CSS as the second has precedence over the first; the first is discarded. To combine transform entries it should be:
-webkit-transform: rotate(15deg) scale(2);
How can I accomplish such CSS to be generated by LESS, i.e. multiple transform entries that are combined correctly?

Starting from Less v1.7.0, merging property values with a space separator is possible and there is no need to club the two mixins into one.
The below Less code
.rotate(#deg) {
-webkit-transform+_: rotate(#deg);
}
.scale(#factor) {
-webkit-transform+_: scale(#factor);
}
div{
.rotate(45deg);
.scale(1.5);
}
will compile into the following CSS:
div {
-webkit-transform: rotate(45deg) scale(1.5);
}

Provide your transforms as arguments for a single mixin:
.transform(#scale,#rotate) {
-webkit-transform: #arguments;
}
I guess, you also could achieve to concatenate your separate mixins into one with the help of guards, but I'm not entirely sure;)
I think you are not able to achieve this in another way, since the parser would have to modify code afterwards which should not be possible.

I think there is a simple way over it, create a div container for the eleemnt, and apply first transform to the cntainer, leaving the second one for the element itself

I was having problems getting #arguments to work. I used the #rest variable which did the trick
LESS example:
.transform(#rest...) {
transform: #rest;
-ms-transform: #rest;
-webkit-transform: #rest;
}
.someClass{
.transform(translate3D(0,0,0),scale(1,1));
}
.otherClass{
.transform(translate3D(0,0,0),rotate(1,1));
}
.anotherClass{
.transform(rotate(1,1));
}
Output CSS:
.someClass {
transform: translate3D(0, 0, 0) scale(1, 1);
-ms-transform: translate3D(0, 0, 0) scale(1, 1);
-webkit-transform: translate3D(0, 0, 0) scale(1, 1);
}
.otherClass {
transform: translate3D(0, 0, 0) rotate(1, 1);
-ms-transform: translate3D(0, 0, 0) rotate(1, 1);
-webkit-transform: translate3D(0, 0, 0) rotate(1, 1);
}
.anotherClass {
transform: rotate(1, 1);
-ms-transform: rotate(1, 1);
-webkit-transform: rotate(1, 1);
}

Related

How to create a 'transform' mixin in SCSS that uses several arguments?

I want to create a mixin for transform that has two arguments - translate and rotate. I've tried it in several ways but none of them works and I do not know why.
#mixin transform($transforms) {
-moz-transform: $transforms;
-o-transform: $transforms;
-ms-transform: $transforms;
-webkit-transform: $transforms;
transform: $transforms;
}
#mixin rotate ($deg) {
#include transform(rotate(#{$deg}deg));
}
#mixin translate($x, $y) {
#include transform(translate($x, $y));
}
In nav.scss I included it like this
#include transform(rotate(45));
#include transform(translate(0,9px));
It doesn't change anything in the presentation page.
Without mixin I simply use:
span:before {
transform: translateY(9px) rotate(45deg);
}
and it works but I want to achieve the same result with a mixin, but I don't know how. I started learning SASS a few days ago.
In general, I would recommend you use Autoprefixer to handle vendor prefixes as you'll often add way more prefixes than needed.
In the case of transform, you would probably be fine just adding
-webkit-transform: ...;
transform: ...;
Also, it becomes rather hard to handle when you need to deal with property values:
transition: transform 300ms;
// prefixed
-webkit-transition: -webkit-transform 300ms;
transition: -webkit-transform 300ms;
transition: transform 300ms;
transition: transform 300ms, -webkit-transform 300ms;
To answer your question I think the easiest way is to use argument-lists (allows any number of arguments to be passed) joined together in a space-separated list:
// Mixin
#mixin transform($transforms...) {
// combine the passed transforms into a space separated list
$transform-list: join($transforms, null, space);
// print out the transforms
-webkit-transform: $transform-list;
-moz-transform: $transform-list;
-ms-transform: $transform-list;
-o-transform: $transform-list;
transform: $transform-list;
}
// Include
span::before {
#include transform(
rotate(90deg),
translate(0,9px),
// ... add more transforms if you need
);
}
// CSS output
span::before {
-webkit-transform: rotate(90deg) translate(0, 9px);
-moz-transform: rotate(90deg) translate(0, 9px);
-ms-transform: rotate(90deg) translate(0, 9px);
-o-transform: rotate(90deg) translate(0, 9px);
transform: rotate(90deg) translate(0, 9px);
}
I don't think that you need to nest the mixins like that. You can take advantage of optional arguments and the keyword syntax:
#mixin transformNew($rotate: 0, $translate: translate(0, 0)) {
-moz-transform: rotate(#{$rotate}deg) $translate;
-o-transform: rotate($rotate) $translate;
-ms-transform: rotate(#{$rotate}deg) $translate;
-webkit-transform: rotate(#{$rotate}deg) $translate;
transform: rotate(#{$rotate}deg) $translate;
}
div {
#include transformNew($translate: translate(10px, 40px));
background: red;
}
The arguments for the mixin now have a default value, if you want to call it with only one argument. You can call arguments explicitly by using the keyword syntax. In my example I wanted only the second argument, so I did this: #include transformNew($translate: translate(10px, 40px));. If you only need the first argument, then it is enough to just pass the value, no need for the keyword.
If you need both arguments, you can simply pass them both. In your code, if you called the mixin twice, you had overwritten the first value with the second call.
That won't happen here. I also created a codepen for you to play around with the code.

CSS :focus to permanently alter a sibling

I have the following working but want the change to stick also when the field is no longer in focus.
I there any way of doing that within CSS?
.contact-field:focus ~ .label {
transform: translate3d(0px, -26px, 0px) scale3d(0.8, 0.8, 1) rotateX(0deg) rotateY(0deg) rotateZ(0deg) skew(0deg, 0deg);
transform-style: preserve-3d; opacity: 0.7;
}
</style>
CSS is intended for styling the page, not to change state. There are hacks that could do what you want to do, but in the end they will all fail one way or another depending on the browser environment.
It's much clearer (and more robust) to use JS for this:
document.querySelector('.contact-field').addEventListener('focus', () => {
document.querySelector('.contact-label').classList.add('visited')
});
I got a friend to help me out.
This did the trick:
$('.contact-field').on('focus', function(){
$(this).addClass('visited');
})
And then the CSS:
.contact-field:focus ~ .label-in-footer,
.contact-field.visited ~ .label-in-footer {
transform: translate3d(0px, -26px, 0px) scale3d(0.8, 0.8, 1) rotateX(0deg) rotateY(0deg) rotateZ(0deg) skew(0deg, 0deg);
transform-style: preserve-3d; opacity: 0.7;
}

Why $rotation variable in scss not parse in filter: progid:DXImageTransform.Microsoft.BasicImage

Compiled css
.fa-rotate-90 {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg); }
SCSS
$fa-css-prefix : 'fa';
#mixin fa-icon-rotate($degrees, $rotation) {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);
-webkit-transform: rotate($degrees);
-moz-transform: rotate($degrees);
-ms-transform: rotate($degrees);
-o-transform: rotate($degrees);
transform: rotate($degrees);
}
.#{$fa-css-prefix}-rotate-90 { #include fa-icon-rotate(90deg, 1); }
Why I got unexpected result filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation);
Can anyone please point out what mistake in this scss.
As I had mentioned earlier in comments, for this case we need to make use of interpolation like in the below code block to get the value of the $rotation variable printed. The syntax for interpolation is #{$var}. Interpolation is required because the variable's value needs to be placed within another string and then the whole thing needs to be assigned as the value to a property.
$fa-css-prefix : 'fa';
#mixin fa-icon-rotate($degrees, $rotation) {
filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=#{$rotation});
-webkit-transform: rotate($degrees);
-moz-transform: rotate($degrees);
-ms-transform: rotate($degrees);
-o-transform: rotate($degrees);
transform: rotate($degrees);
}
.#{$fa-css-prefix}-rotate-90 { #include fa-icon-rotate(90deg, 1); }

Using LESS / CSS / Mixins and passing values from classes

I have this little snippet of css which i want to use transform and then add rotate into it but getting a failure... am i doing this wrong? Im new to LESS so sorry if im going about this wrong.
CSS:
.class {
&::before {
.transform(.rotate(#deg: 45deg));
}
&::after {
.transform(.rotate(#deg: -45deg));
}
}
MIXIN:
.transform(#string){
-webkit-transform: #string;
-moz-transform: #string;
-ms-transform: #string;
-o-transform: #string;
}
.rotate (#deg) {
-webkit-transform: rotate(#deg);
-moz-transform: rotate(#deg);
-ms-transform: rotate(#deg);
-o-transform: rotate(#deg);
}
So the way you have things set up above, you're basically passing the entire rotate mixin into the transform mixin. Which, if it actually knew how to parse, would end up with pretty garbled code. Instead, you can just use the top mixin and pass rotate into it. This is a better route, because it would allow you to use multiple transforms (which is a pretty common usage). Here's an example:
.transform(#string){
-webkit-transform: #string;
-moz-transform: #string;
-ms-transform: #string;
-o-transform: #string;
}
.class {
&::before {
.transform(rotate(45deg));
}
}
And if you wanted to call rotate and translate at a future time, it would be as easy as adding translate, as well.
.class {
&::before {
.transform(translateY(-50%) rotate(45deg));
}
}

How to scale and translate3d at the same time?

Take this example:
#-webkit-keyframes slideInViewport {
from{
-webkit-transform: scale(1);
-webkit-transform: translate3d(0, 0, 0);
}
to{
-webkit-transform: scale(0.8);
-webkit-transform: translate3d(250px, 0, 0)
}
}
This results in the div first translating 250px to the left and then scaling. How can I make it translate3d at the same time it is scaling?
I have achieved this animating on the left property, but that results in very poor performance.
The solution is: put them all in one line.
#-webkit-keyframes slideInViewport {
from{
-webkit-transform: scale(1) translate3d(0, 0, 0);
}
to{
-webkit-transform: scale(0.8) translate3d(250px, 0, 0);
}
}

Resources