Using #mixin to achieve RTL support on Angular - css

I am using a mixin to convert my Angular app from LTR to RTL accordingly.
#mixin rtl($property, $ltr-value, $rtl-value) {
[dir='ltr'] & {
#{$property}: $ltr-value;
}
[dir='rtl'] & {
#{$property}: $rtl-value;
}
}
#mixin rtl-prop($ltr-property, $rtl-property, $value) {
[dir='ltr'] & {
#{$ltr-property}: $value;
}
[dir='rtl'] & {
#{$rtl-property}: $value;
}
}
When I use #include, for some reason it doesn't work. (html tag is defined properly)
#include rtl(border-radius, 0 10px 80px 0, 0 80px 10px 0);
<html lang="he" dir="rtl">
Any ideas why?

For those who will encounter this issue at the future, the problem was component's encapsulation - it was set to Emulated which probably interfered with the classes names.
Set it to None instead.

There are a couple of things you can do to solve this, but that are not optimal:
First and for all you are checking if the component itself has dir set, that is why it isn't working. Because the direction is set on the tag.
You can try to use :host-context, because than it will take a look at the html attribute and not your component. Like this:
#mixin rtl($property, $ltr-value, $rtl-value) {
:host-context([dir='ltr']) & {
#{$property}: $ltr-value;
}
:host-context([dir='rtl']) & {
#{$property}: $rtl-value;
}
}
But always check on canIUse to see if it has enough coverage. For this moment it is around 75% so I would say it is too low, certainly if you have a lot of mobile iOS users.
Another alternative to :host-context() is :dir(), but this has on the moment of writing only 3% coverage, so I would not bother using that either.
The currently approved answer (the one that suggests to set encapsulation to None) is not recommended since it will make all the mark-up for that component global and could cause some unexpected issues. Certainly because direction is maybe something you'd want to use in almost all of your components.
I think the best solution right now is to use logical properties from css. You use 'start' instead of 'left' for example. You can google it and find a lot of info to use it. (for example on developer mozilla site).
For your example you would have to use:
.yourClass {
border-start-start-radius: 0;
border-start-end-radius: 10px;
border-end-start-radius: 80px;
border-end-end-radius: 0;
}
And this would make it look the way you want it on any text-direction without the use of any mixins.

Related

Transform properties/variables clashing in sass and overwriting eachother

I have the code at the bottom of the page in my sass. In my html I am targeting it as follows
class=" transform rotate-5 zoom-2 ......"
the problem is that the transform properties are clashing and aren't applying scale and rotate to the same div tag, I'm either getting one or the other.
I thought I could change this by using the #extend property and something like,
&.rotate-#{$i}
{#extend &.skew-#{$i}, &.zoom-#{$i}, &.zoom--#{$i};
transform: rotate($rotate#{deg});
}
but so far I've had no luck, if anyone can help it'd be greatly appreciated.
.transform {
overflow:hidden;
#for $i from 1 through 360 {
$rotate: $i;
$skew: $i;
$zoom: $i;
&.rotate-#{$i} {
transform: rotate($rotate#{deg});
}
&.skew-#{$i} {
transform: skew($skew#{deg});
}
&.zoom-#{$i} {
transform: scale($zoom,0);
}
&.zoom--#{$i} {
transform: scale(-$zoom,0);
}
}
}
I'm a big fan of utility classes that I thought easier to debug and to build with. But here it doesn't seem to be a good idea:
1) You are creating 360 * 4 selectors, yet you will probably only use 10-20 of them. It is a bit overkill.
2) As you describe it, the transform property values do not "combine" well, at least for what you are looking for. Even atomic CSS, which pushes very far the utility classes approach, specificies that combining different values of filter (for instance) needs creating a custom value / class.
I understand that it is not really a good answer, at least not the answer you were looking for, but if you want to keep your CSS only approach, I suggest you adopt a more "object-oriented" method for this issue and set your transform property directly in the css of your object, for instance with this mixin:
#mixin transform($rotate, $skew, $zoom) {
transform: rotate($rotate#{deg}) skew($skew#{deg}) scale($zoom,0) scale(-$zoom,0);
}

Add !important to all styles for widget without javascript

I am building a widget that will be displayed on a client's site. We cannot use an iFrame so I am forced to use an exhaustive CSS reset (https://github.com/premasagar/cleanslate) to avoid interference with their styles. To use that solution, I need to add !important to all of my styles and because there are a lot of them and I want to keep this code easy to maintain, I'm looking for a more dynamic solution.
I am able to add !important to the stylesheet via javascript but that's not ideal for a production environment. I am using CodeKit and LESS and wondering if either of these are able to help me easily add !important to all styles when the CSS file is generated.
Mixin?
CodeKit config?
Update: Yes, LESS Can Help
I hate using !important except in the most extreme circumstances. Most people use it like a chainsaw when they should be using a scalpal to do the job. Nevertheless, I understand the issues facing widget developers like yourself, and your choice to use https://github.com/premasagar/cleanslate leaves you with no option.
Marc's answer noted a good feature of LESS, but he failed to demonstrate how that can help in this matter.
If you wrap your entire LESS code in a namespaced mixin, then this feature does exactly what is needed. So assume your widget code looked like this (you mentioned you are already using some type of class for your widget):
.yourWidgetClass div > p {
prop: something;
&:hover {
prop: some-hover-style;
}
}
.yourWidgetClass .someClass {
prop: something;
}
Then you can do this (wrapping all your widget code in #makeImportant() then calling that mixin with the !important feature noted in Marc's answer):
#makeImportant() {
.yourWidgetClass div > p {
prop: something;
&:hover {
prop: some-hover-style;
}
}
.yourWidgetClass .someClass {
prop: something;
}
}
& {
#makeImportant() !important;
}
This produces the following CSS Output:
.yourWidgetClass div > p {
prop: something !important;
}
.yourWidgetClass div > p:hover {
prop: some-hover-style !important;
}
.yourWidgetClass .someClass {
prop: something !important;
}
For my original (accepted) answer that was way more manually intensive, see the edit history.
I found that LESS can mark all properties set by a mixin at once as !important when specify !important after the mix-in call.
.someMixin() {
background-color: #fff;
cursor: pointer;
}
.someUsages {
.someMixin() !important;
}
Results in:
.someUsages {
background-color: #fff !important;
cursor: pointer !important;
}
For more information on this topic see the LESS doc about "The !important keyword".

How do I implement OOCSS' spacing module in SCSS?

I've got a SCSS-based layout in which I want to use the spacing module from OOCSS.
The OOCSS module is pure CSS - ptl, for example, stands for padding-top: large, where large is a defined value (by default 20px).
I'd like to enhance it with SCSS. So far I've been able to replace the fixed values with SCSS variables, so I can change the values in one place if I want to (I don't want to):
$spacing-small: 5px;
$spacing-medium: 10px;
$spacing-large: 20px;
...
.pts,.pvs,.pas{padding-top:$spacing-small !important}
Now I'd like to be able to use ptn,pvs, etc. as mixins, so I can do this:
.client-name {
#include spacing-pvs; // this has the same padding properties as pvs
}
I'm flexible in the syntax, but that's the functionality I'd be interested in having.
The only way I can think of for doing this is manually defining every single mixin:
#mixin spacing-pvs {
padding-top: $spacing-small !important;
padding-bottom: $spacing-small !important;
}
.pvs { #include spacing-pvs; }
But there are around 56 styles/mixins. Doing each one individually like this would be pain to write and to maintain.
Is there a better way to do this in SASS/SCSS?
The most efficient mixin would be like this (you'll need a similar mixin for padding, or add an extra argument to switch between margin/padding):
#mixin marginify($t: null, $r: null, $b: null, $l: null) {
margin-top: $t;
margin-right: $r;
margin-bottom: $b;
margin-left: $l;
}
.test {
#include marginify($t: 10px, $b: 10px);
color: green;
}
Which generates this:
.test {
margin-top: 10px;
margin-bottom: 10px;
color: green;
}
The null (available in Sass 3.2+) is doing its magic here: if a variable is null, then it doesn't generate a property for it. However, you have to give up the use of !important (most people would argue that you should only use it as a last resort anyway). Reliance on this mixin is going to introduce a fair bit of bloat because the longhand form is always used over the shorthand (margin: 10px 0), so you'll need to use it responsibly or write a more powerful mixin that will generate the shorthand if appropriate.
That said, using a mixin for this purpose (adding margins) does reduce readability in your code. Before I looked at the entire source, the names made no sense. There's a lot to be said about the readability of vanilla CSS. The marginify mixin isn't really a reusable pattern like a clearfix or inline-menu mixin might be: writing a mixin isn't just about saving keystrokes.
I ended up not using mixins at all. Instead, I left the CSS rules as they were, and I used this less documented feature called #extend. Behold!:
.client-name {
#extend .pvs; // this has the same padding properties as .pvs
}

SASS 3.2 Media Queries and Internet Explorer Support

I recently implemented this technique with SASS 3.2 using #content blocks on a project I've been working on, and I've just gotten to the point where I need to include support for older browsers such as IE7 and 8.
Example:
.overview {
padding: 0 0 19px;
#include respond-to(medium-screens) {
padding-top: 19px;
} //medium-screens
#include respond-to(wide-screens) {
padding-top: 19px;
} //medium-screens
}
They both don't support media queries, and I've often handled this in the past by serving up all styles to these browsers when I had my media queries separated into separate partial files such as _320.scss, _480.scss and in my IE stylesheet loading them like so:
#import 320.scss;
#import 480.scss;
etc.
Which would load all styles, and always assign IE7 - 8 a 940px (or whatever the max width is) layout and styles. By nesting styles in SASS 3.2 inline like this, it eliminates the need for separate partial stylesheets, but totally screws up how I load styles for IE.
Any ideas or solutions on how to combat this? I could use a polyfill such as respond.js to force IE to use media queries, but would prefer to just serve up a non-flexible site to IE.
Any ideas on either how to best organize these files, or a better solution?
You can generate a separate stylesheet for IE<9 that contains everything your normal sheet has, but with flattened media queries based on a set width.
Full explanation here http://jakearchibald.github.com/sass-ie/, but basically you have this mixin:
$fix-mqs: false !default;
#mixin respond-min($width) {
// If we're outputting for a fixed media query set...
#if $fix-mqs {
// ...and if we should apply these rules...
#if $fix-mqs >= $width {
// ...output the content the user gave us.
#content;
}
}
#else {
// Otherwise, output it using a regular media query
#media screen and (min-width: $width) {
#content;
}
}
}
Which you'd use like this:
#include respond-min(45em) {
float: left;
width: 70%;
}
This would be inside all.scss, which would compile down to all.css with media queries. However, you'd also have an additional file, all-old-ie.scss:
$fix-mqs: 65em;
#import 'all';
That simply imports all, but flattens media query blocks given a fake width of 65em.
I use LESS for a lot of my work, but on larger projects, with many people working across files, I don't like using breakpoint files, such as 1024.less.
My and my team use a modular approach, such as header.less which contains all the code for just the header, including the associated breakpoints.
To get round IE problems (we work in a corporate environment), I use this approach:
#media screen\9, screen and (min-width: 40em) {
/* Media queries here */
}
The code inside the media query is always executed by IE7 and less. IE9 and above obeys the media queries like a proper browser should. The problem is IE8. To solve this, you need to make it behave like IE7
X-UA-Compatible "IE=7,IE=9,IE=edge"
I've found this doesn't always work if set in the metatags in the HTML, so set it using the server headers.
See the gist here:
https://gist.github.com/thefella/9888963
Making IE8 act like IE7 isn't a solution that works for everyone, but it suits my needs.
Jake Archibald has the best technique I've seen to date for achieving this. This technique automatically creates a separate stylesheet for IE, with all the same styles inside of your media queries but without the media query itself.
I also campaigned to get this technique built into the popular breakpoint extension for Sass, if you're interested in using that!
If you wanted to keep everything under one roof and only have a single http request for your older browser visitors you could do something like this
Setting up your initial respondto mixin
// initial variables set-up
$doc-font-size: 16;
$doc-line-height: 24;
// media query mixin (min-width only)
#mixin breakpoint($point) {
#media (min-width: $point / $doc-font-size +em) { #content; }
}
this will create a min-width media query and output your px value ($point) as an em value.
From this you'd need to create this mixin
#mixin rwdIE($name, $wrapper-class, $IE: true) {
#if $IE == true {
.lt-ie9 .#{$wrapper-class} {
#content;
}
.#{$wrapper-class} {
#include breakpoint($name) {
#content;
}
}
}
#else if $IE == false {
.#{$wrapper-class} {
#include breakpoint($name) {
#content;
}
}
}
}
Here if you pass a piece of Sass(SCSS) like this
#include rwdIE(456, test) {
background-color: #d13400;
}
it will return this code
.lt-ie9 .test {
background-color: #d13400;
}
#media (min-width: 28.5em) {
.test {
background-color: #d13400;
}
}
This will give you the you the IE and 'new browser' CSS in one file. If you write -
#include rwdIE(456, test, false) {
background-color: #d13400;
}
You will get -
#media (min-width: 28.5em) {
.test {
background-color: #d13400;
}
}
I hope this helps, I've got this on a codepen here too - http://codepen.io/sturobson/pen/CzGuI
There is a CSS3 Mixin I use that has a variable for IE filters. You could do something similar by having a global variable, $forIE or something, wrap the media query mixin within an if and then generate the stylesheet with or w/o the queries.
#if $forIE == 0 {
// Media Query Mixin
}
Or use the #if to import a 3rd scss (_forIE.scss?) that will override things with your IE specific styles.

Declare a global CSS property ? Is this possible?

I have a very wierd question, I dont know wether if its possible in css or not
Suppose I have say 3 different css classes as shown below, as you can see I have a common property of all these classes, I want to declare this color somewhere else and pass a reference to it here, so if next time I want to change the color I can simply change at one place rather than changing in all the 5 classes.
I know that you can use body{}, or a wrapper for this but that would affect the colors of the entire site right ? Is there a way to do this ?
Is this even possible ?
.abc {
color:red;
}
.abc2 {
color:red;
}
.abc3 {
color:red;
}
.abc4 {
color:red;
}
.abc5 {
color:red;
}
The bad news: you can't do it in CSS.
The good news: you can write in a meta-CSS language like LESS, which then processes a LESS file to pure CSS. This is called a "mixin".
In LESS:
#errorColor: red;
.error-color {
color: #errorColor;
}
#error-1 {
.error-color;
}
.all-errors {
.error-color;
}
More info: http://lesscss.org/#-mixins
if you want to declare all of them at a time, you can use:
.abc, .abc2, .abc3, .abc4, .abc5 {
color:red;
}
Or you can declare an additional class & add to all the .abc, .abc2.... & make its color:red;.
This can not be done with CSS, but that is still a very popular thing to do by using a CSS preprocessor such as LESS, SASS, SCSS, or Stylus.
A preprocessor will let you define a variable (say $red = #F00). It will replace the variable in your CSS document with the variable value for you, allowing you to write very DRY and module CSS.
This functionality is referred to as "CSS variables", which is part of the future spec, but not yet implemented on any browsers.
For now, the best way to do this in pure CSS is to declare an additional class for the desired "global", and then add that class to all relevant items.
.abc_global { color: red; }
.abc1 { /* additional styling */ }
.abc2 { /* additional styling */ }
<div class="abc1 abc_global"></div>
<div class="abc2 abc_global"></div>
With LESS
You are able to define that red color once:
.myRedColor {
color:red;
}
Now you can call that red on any CSS styles. Even NESTED styles! It's a wicked tool!
.abc1 {
.myRedColor;
}
.abc2 {
.myRedColor;
}
.abc3 {
.myRedColor;
}
.abc4 {
.myRedColor;
}
NESTED EXAMPLE:
.abc {
.itsEasyAsOneTwoThree{
.myRedColor;
}
}
Now all of our "itsEasyAsOneTwoThree" classes that are properly nested inside of an "abc" class will be assigned the red style. No more remembering those long #867530 color codes :) How cool is that?!
You can also use PostCSS with the plugin postcss-preset-env and support custom properties/variables, then use the :root selector to add global css variables.
:root {
--color-gray: #333333;
--color-white: #ffffff;
--color-black: #000000;
}

Resources