Susy change flow from rtl to ltr if a class exists - css

I need the $susy variable to change from rtl to ltr if an ar class exists in body. I need to do it to support multi lingual on my site,below is the code for the same
.page-container {
background-color: red;
#include container($susy);
#include susy-breakpoint($medium) {
background-color: yellow;
#include container($susy-medium);
}
#include susy-breakpoint($large) {
background-color: lightgreen;
#include container($susy-large);
}
&.ar {
//change flow to rtl
}
}
$medium: 768px; //tab
$large: 1024px; //desktop
//susy grid params small
$column-numbers-small: 6;
$column-width-small: 40px;
$column-gutter-small: 16px;
$available-width-small: 336px;
//susy grid params medium
$column-numbers-medium: 12;
$column-width-medium: 42px;
$column-gutter-medium: 20px;
$available-width-medium: 744px;
//susy grid params large
$column-numbers-large: 12;
$column-width-large: 86px;
$column-gutter-large: 24px;
$available-width-large: 1320px;
$susy: (
container: $available-width-small,
container-position: center,
columns: $column-numbers-small,
math: fluid,
output: isolate,
gutter-position: split,
gutters: $column-gutter-small/$column-width-small,
);
$susy-medium: (
container: $available-width-medium,
container-position: center,
columns: $column-numbers-medium,
math: fluid,
output: isolate,
gutter-position: split,
gutters: $column-gutter-medium/$column-width-medium,
);
$susy-large: (
container: $available-width-large,
container-position: center,
columns: $column-numbers-large,
math: fluid,
output: isolate,
gutter-position: split,
gutters: $column-gutter-large/$column-width-large,
);
$susy-large-ar: (
flow: rtl,
container: $available-width-large,
container-position: center,
columns: $column-numbers-large,
math: fluid,
output: isolate,
gutter-position: split,
gutters: $column-gutter-large/$column-width-large,
);
Can somebody please suggest how to override this flow direction dynamically.

This isn't possible in the way you've currently framed it. One of the major limitations of using a preprocessor (like Sass) is that variables do not have access to the DOM. That means there is no way to change a variable based on a body class. There are a few ways to work around that, but none of them are simple and fully dynamic. Basically, you have to create duplicate styles for each direction.
Option 1: Separate Output CSS
Some people do that with separate ltr and rtl stylesheets. Rather than adding a class to flip direction, you load a different stylesheet. To make the Sass work, create two sass files (e.g ltr.scss and rtl.scss) – and set them up like this:
// set your flow at the top of each document…
$flow: (flow: rtl);
Then put all your actual styles in Sass "partials" (_filename). One of those partials can merge the new flow into your existing variables:
// Merge flow with other Susy settings…
$susy: map-merge($susy, $flow);
$susy-medium: map-merge($susy-medium, $flow); // etc…
Then import your partials into each document. This way you can compile the same code, with different variables…
#import 'flow-setup';
#import 'actual-style-partials';
Option 2: Inline Duplication
The other option I've seen people use to create a class system (rather than split stylesheets) gets kinda bulky in your code:
.element {
#include span(3 of 12);
.rtl & {
#include span(3 of 12 rtl);
}
}
You can write a mixin to do that for you automatically:
#mixin flow-span($details) {
#include span($details);
$rtl: append($details, rtl);
.rtl & {
#include span($rtl);
}
}
You would have to do the same thing for every Susy mixin you use.
Sorry neither option is simple, but that's about the best you can do in a pre-processor.

Related

Sass Grid System - Implementing gutters

I am trying to implement gutters for the following code(https://www.sassmeister.com/gist/eca78ee1435202c7e7dcaecc57c75bd5):
// ----
// Sass (vundefined)
// Compass (vundefined)
// dart-sass (v1.6.2)
// ----
//Variable Declarations
$__grid--columns:12;
$__grid--breakpoints: (
'xxxsmall': 375px,
'xxsmall': 480px,
'xsmall': 667px,
'small': 768px,
'medium': 960px,
'large': 1024px,
'xlarge': 1200px,
'xxlarge': 1400px,
'xxxlarge': 1600px,
);
$__grid--gutters: (
'small': 30px,
'medium': 30px,
'large': 30px
);
$__grid--cell-containers: (
'small': 1200px,
'medium': 1400px,
'large': 1600px,
'full': 100%
);
//Mixins for Grid
// #mixin createGutters() {
// .element {
// #if map-has-key($__grid--gutters, '') {
// content: 'Key Found';
// } #else {
// content: 'Key Not Found';
// }
// }
// }
#mixin createCells() {
#each $key, $value in $__grid--breakpoints {
#media screen and (min-width:$value){
#for $i from 1 through $__grid--columns {
&.#{$key}-#{$i}{
#if map-has-key($__grid--gutters, $key) {
margin-left:map-get($__grid--gutters, $key);
}
width:((100% / $__grid--columns) * $i);
}
}
}
}
}
//Spit out the cells
.row {
display:flex;
flex-wrap:wrap;
}
.cell {
// #include createGutters;
#include createCells;
}
//Styles not needed for grid
// * {
// box-sizing:border-box;
// }
// .color {
// padding:10px;
// background-color:salmon;
// }
As you can see I have a sass map for the gutters. I am trying to keep this as simple as possible. I'm not sure if I should be using an each loop, or a map-get() function, or maybe something else. I also want to have the margins on the left. I have to consider that if their are too many columns they will drop to the next line.
So basically if I set the margin of the first element to 0, and I have 4 columns that will fit within the container, the 5th item onward on will drop to the next line. The problem is that the margin on the 5th item will still be there.
This is a representation of what I mean:
item---item---item---item
---item---item---item---item
---item---item---item---item
So is there a way to:
Implement my sass map in a succinct way?
Add in support for if the items break to the next line for the margin
Better way to do this process? If so, feel free to fork the sassmeister code.
Your questions contains several points so I will try to answer them in an order that, think, will work better.
Normally purpose of the grid system (or columns system, to name it better to avoid names collision with CSS Grid specification) is to simplify elements positioning by providing ability for elements to take space of one or multiple "columns" defined by the grid. This definition means that columns can't wrap, so your flex-wrap: wrap breaks whole idea of columns system.
Your column width math width:((100% / $__grid--columns) * $i); does not include the fact that grid consists not just of columns, but also of gutters between them. Usually gutters are available only between columns so for 12-columns grid you need to have 11 gutters of defined size. It means that your actual math for grid column width should use calc() expression and it actual math will look like: width: calc(#{100% / $__grid--columns * $i} - #{$gutter-size / $__grid--columns * ($__grid--columns - $i)}); where $gutter-size is current gutter size. I've prepared a CodePen example to demonstrate this math.
If you want your grids to be even better - it is worth to let grid maths to be performed by dedicated library. Try to use Susy 3 for this purpose and your result will became much better.

How to apply a given width/margin in singularity.gs?

I am using singularity.gs (Drupal 7/Omega 4), and I want to stack my content in columns.
In 960gs, you just add grid-4 to the element, and it spans 4 columns with appropriate margins (more or less).
To make a 12-column grid with sigularity.gs I've written this:
.grid-4 {
width: column-span(4, 6);
margin-left: gutter-span();
float: left;
}
.grid-4:first-child {
margin-left: 0;
}
Is there a simpler or more idiomatic way to do it?
I'm not sure if this is a question per se, but I think I can answer it.
Singularity allows different output styles to provide their own span mixins to better adhere to that output style's mental model. 960gs works on the float output style, allowing you to to change what you have to the following:
.grid-4 {
#include float-span(4);
&:nth-of-type(3n) {
#include float-span(4, 'last');
}
}
A working SassMeister with this should give you a clear idea of what's going on.

Bourbon neat not behaving as expected in my mobile-first setup

I'm using bourbon neat for the first time and it's not behaving exactly how I would expect - which probably means I've set things up wrong.
I'm developing mobile-first, so I would expect my layout to remain the same between my desktop breakpoint and my larger breakpoint (for the styles to cascade to the next breakpoint). However, my layout jumps back to the mobile layout unless I redefine the styles again in the larger breakpoint.
Here is how I've defined my breakpoints in my base/_grid-settings.scss:
// Neat Overrides
$grid-columns: 4;
$max-width: 90%;
// Breakpoints
$first-breakpoint-value: 641px;
$second-breakpoint-value: 1024px;
$third-breakpoint-value: 1440px;
$fourth-breakpoint-value: 1920px;
$tablet: new-breakpoint(min-width em($first-breakpoint-value) max-width em($second-breakpoint-value) 8 );
$desktop: new-breakpoint(min-width em($second-breakpoint-value + 1) max-width em($third-breakpoint-value) 12 );
$large: new-breakpoint(min-width em($third-breakpoint-value + 1) max-width em($fourth-breakpoint-value) 12 );
$xlarge: new-breakpoint(min-width em($fourth-breakpoint-value +1) 12 );
Then my element looks like this:
.container {
#include outer-container;
.swatch {
// mobile styles (here my swatch has a width of 100%)
border: 1px solid #000;
text-align: center;
margin-bottom: $gutter;
//MEDIA QUERIES
#include media($tablet) {
#include span-columns(4);
#include omega(2n);
}
#include media($desktop) {
#include span-columns(3);
#include omega(4n);
padding: 2em -0px;
}
#include media($large) { }
#include media($xlarge) { }
}
}
Now I was expecting the styles from my $desktop media query to cascade all the way up to the $xlarge media query, however currently the .swatch element jumps back to being 100% of it's parent container at the $large and $xlarge breakpoints.
What have I done wrong?
I shouldn't need to keep repeating the same code for every breakpoint if I want the styles to cascade up.
You are defining a media query range, which is why it is snapping back to the mobile view in between.
Remove the max value from your breakpoint and the values will cascade up to desktop.
Im not too familiar with neat but the following should work:
$tablet: new-breakpoint(min-width em($first-breakpoint-value) max-width em($second-breakpoint-value) 8 );
becomes:
$tablet: new-breakpoint(min-width em($first-breakpoint-value) 8);
Hope this helps you or any one else reading this post, I had a similar issue and found this handy omega reset mixin.
http://www.joshfry.me/blog/2013/05/13/omega-reset-for-bourbon-neat
Thanks #nickspiel - that was half the answer! You are correct, adding min-with only breakpoints is the way to get the styles to cascade up the breakpoints. Doing that with Bourbon Neat and an element that is using omega is a bit more tricky.
It seems that I have 2 choices:
Use media query splitting, as per the docs, but then you need to set styles for every breakpoint.
Use your suggestion of min-width breakpoints in conjunction with an Omega reset - I'm going with this option.

susy 2.0 change columns at breakpoint

I'm not using Compass
I prefer to use Breakpoint.scss
I'm on susy 2.0
I know there are lot of posts with this question but I'm having 0 luck finding any regarding Breakpoint.scss and Susy 2.0 on this topic.
#import "susy";
#import "breakpoint";
$medium: 800px;
$susy: (
columns: 6,
gutters: 3/4,
gutter-position: split
);
#include breakpoint($medium) {
$susy: layout(12 1/4 split);
}
body {
#include container(show);
#include breakpoint($medium) {
#include container(show);
}
}
Do I have to use susy-breakpoint or can something like this be achieved?
I want 6 columns at anything at/below 800px and 12 at/above 800px
I'm trying to stay DRY so adding a susy-breakpoint in my styles does not help.
I've also tried below code but I think I just have an error somewhere cause it's not working.
$susy: layout(6 1/4 split);
$small: 400px, 6 1/4 split;
$medium: 800px, 8 1/4 split;
$large: 1000px, 12 1/4 split;
#mixin media($size) {
#include susy-breakpoint($size...) {
#content;
}
}
body {
#include container(show);
#include media($small) {
#include container(show);
}
// debugging. didnt work either
#include susy-breakpoint($small...) {
#include container(show);
}
}
I don't know what your media mixin does, so I can't really comment on anything related to that. Your initial example doesn't work because Sass, CSS, and therefor Susy, are not aware of the DOM - or relationships between media-queries. When you change the value of $susy inside one media-query, that does not propagate to all similar media-query contexts. Because of that, you do have to set both the media-query and the desired layout every time you want a breakpoint to change the layout context.
susy-breakpoint is not the only way to do that, but it is the shortest. Here's the longhand:
body {
#include container(show);
#include breakpoint(800px) {
#include with-layout(8) { // default is set to 8-columns
#include container(show);
} // default is returned to global setting
}
}
Your $small breakpoint currently doesn't change anything, because it is identical to your default layout. The larger ones will change the layout context for nested code — though you can simplify: Since `1/4 split' gutters aren't changing at all, they don't need to be re-stated at every breakpoint.
$susy: layout(6 1/4 split);
$medium: 800px, 8;
body {
#include container(show);
#include susy-breakpoint($medium...) {
#include container(show);
}
}
That will be identical to the longhand above.

Susy: Omega and Responsive Grids

When using Susy, you put an "omega" flag on the last item of a row to remove its margin-right. For example, let's say we have a bunch of items we need to lay out on a 12-column grid:
<div class="item">...</div>
<div class="item">...</div>
<div class="item">I'm the last of the row</div>
<div class="item">...</div>
And the SCSS:
.item{
#include span-columns(4);
#include nth-omega(3n);
}
But our grid is responsive, and smaller displays use an 8-column grid. The problem is that omega now needs to appear on 2n, and not 3n:
<div class="item">...</div>
<div class="item">I'm the last of the row</div>
<div class="item">...</div>
<div class="item">...</div>
So my question is: with Susy, do you need to redefine your columns for each breakpoint, or is there some way to define column widths once and for all and let the omega naturally fall at the right place?
And if not, does any other grid system offer that?
Solving your issue with Susy
Susy allows overriding the number of columns. Many Susy mixins allow that — every mixin that accepts the $context argument.
But the best way to override a context is with the at-breakpoint mixin:
// Defining the breakpoints
$mobile-to-medium: 400px;
$medium-to-large: 800px;
// Defining columns
$columns-small: 1;
$columns-medium: 8;
$columns-large: 12;
// Starting with a one-column mobile grid
$total-columns: $columns-small;
// Global styles go here
// Mobile-only styles
#include at-breakpoint($total-columns $mobile-to-medium) {
// ...
}
// Medium-only styles go here
#include at-breakpoint($mobile-to-medium $columns-medium $medium-to-large) {
.item{
#include span-columns(3);
#include nth-omega(2n); } }
// Large-only styles go here
#include at-breakpoint($medium-to-large $columns-large) {
.item{
#include span-columns(4);
#include nth-omega(3n); } }
Omega supposes layered responsiveness: mobile styles are applied to all widths; medium styles are applied to medium and large widths, large styles are applied to large widths.
The approach above is not layered: mobile styles are applied only to mobile width, etc. This way you don't need to worry about omega applied where it's not supposed to go.
To use the Omega layered approach, just remove the third element (max-width) in at-breakpoint calls. But then you have to apply #include remove-nth-omega():
// Defining the breakpoints
$mobile-to-medium: 400px;
$medium-to-large: 800px;
// Defining columns
$columns-small: 1;
$columns-medium: 8;
$columns-large: 12;
// Starting with a one-column mobile grid
$total-columns: $columns-small;
// Global styles go here
// Medium and large styles go here
#include at-breakpoint($mobile-to-medium $columns-medium) {
.item{
#include span-columns(3);
#include nth-omega(2n); } }
// Large-only styles go here
#include at-breakpoint($medium-to-large $columns-large) {
.item{
#include span-columns(4);
#include remove-nth-omega(2n);
#include nth-omega(3n); } }
An overview of an omega-less approach
There are SASS grid systems that don't use the "omega" parameter (not to be confused with the Omega theme for Drupal) that's necessary to be applied for the last item in each row. Instead, you provide each element's position (which column the item starts at) in addition to its column width.
To make that possible, another CSS positioning approach is used, known as "isolation". The first framework to use this approach was Zen Grids.
Susy also has support for this method with its isolate and isolate-grid mixins.
This overview would not be complete without mentioning Singularity, the latest and most advanced SASS grid framework. It supports both postioning methods and is extendable to support more in the future (like flexbox which has recently been added to Compass).
In your case, you will have to redefine the total number of columns (context) in the new breakpoint. As for nth-omega, you can use #include remove-nth-omega(3n) to negate the first call before explicitly calling the second, but I consider that a CSS code smell (having to neutralize properties) so I recommend using media-query splitting to avoid that.
Also, I'm not aware of any framework that can automatically do that for you.

Resources