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.
Related
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.
I need to use bootstrap 12 columns grid to get a responsive form based on the parent div's size.
As an exemple, whatever the size of the screen, the content need to see the div A's width and base the bootstrap's responsive design on that width.
My goal is to base my responsive design on the size of a modal window (in dhtmlx). If the user resize the modal window, the row should follow the rules (e.g. col-xs-12, col-sm-6, etc, but based on the size of the modal window, not the screen).
This fiddle show a modal window with some bootstrap form inside. I need the form to be responsive to the size of the modal form, not the screen size.
class="col-xs-12 col-sm-6"
As #makshh mentionned in the comment, it does not seem to be possible to do this right now. The only way I found is from another stack overflow question by #tsdexter:
$(document).ready(function(){
$('.somecontainer').on('resize',function(){
if ($('.somecontainer').width() < 640) {
$('.somecontainer').addClass('m');
} else {
$('.somecontainer').removeClass('m');
}
});
});
I just managed to make the grid system inside a modal act responsive to the modal's breakpoints in Bootstrap 4 with scss. Since the modal's max-width is responsive itself on some breakpoints, we need to generate new css on those breakpoints for that specific modal size (sm, md, lg, xl) which just overrules the Bootstrap's css media queries
Just copy/paste everything into a separate scss file, activate it and you are good to go
// This is a stripped version of the original "make-grid-columns" mixin from Bootstrap
#mixin make-modal-grid-columns($breakpoints) {
#each $breakpoint in map-keys($breakpoints) {
$infix: breakpoint-infix($breakpoint, $breakpoints);
#include media-breakpoint-up($breakpoint, $breakpoints) {
#for $i from 1 through $grid-columns {
.col#{$infix}-#{$i} {
#include make-col($i, $grid-columns);
}
}
}
}
}
$breakpoint-sm: 576px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;
.modal {
// Overrules all .col css inside .modal-sm to a single col
.modal-sm {
#include make-modal-grid-columns((
xs: 0
));
}
// modal-md (no specific class is also modal-md)
#include make-modal-grid-columns((
sm: $breakpoint-sm
));
.modal-lg {
#include make-modal-grid-columns((
md: $breakpoint-lg
));
}
.modal-xl {
#include make-modal-grid-columns((
md: $breakpoint-lg,
lg: $breakpoint-xl
));
}
}
FYI: it generates 350 lines of code
Most Susy examples I've seen seem to handle situations where the amount of columns changes at a given breakpoint, i.e.:
$total-columns: 4;
$large: 12;
// code based on 4 columns
#include at-breakpoint($large) {
// code based on 12 columns
}
But what about when you want the number of columns to remain the same, but (for example) just change the column width? Like this:
$total-columns: 12;
$column-width: 3em;
$large: 64em;
$large-column-width: 3.75em;
#include at-breakpoint($large) {
$column-width: $large-column-width; // automagically changes previously declared column-widths.
}
I would want anything using columns() or span-columns() before the breakpoint to automatically adjust their values to the new column-width without having to redeclare them.
So...
foo { #include span-columns(4, $total-columns); }
would not change at the breakpoint, but the width of the columns would, automatically.
Is this possible?
Susy 2 solves this problem using the new susy-breakpoint with a more powerful shorthand syntax. But the Susy 1 approach isn't much more complex. The at-breakpoint mixin is a simple wrapper for two actions:
Set up a media-query.
Change the global Susy settings inside that media-query block.
I recommend downloading Breakpoint (or another plugin like it) to handle the media-query side of things, but you can also do it by hand. Susy provides a mixin to handle the second part (with-grid-settings). If you put those two together, you have a more powerful version of at-breakpoint.
$large: 64em;
$large-column-width: 3.75em;
#media (min-width: $large) {
#include with-grid-settings($column-width: $large-column-width) {
// new column-width applied to code in here.
}
}
I have written this piece of code to calculate column widths for my grid system:
#mixin calc-width($index, $type) {
$column-calculation: (100% - ($gutter-width-procent * ($column-count - 1))) / $column-count;
$column-width: ($column-calculation * $index);
$gutter: ($gutter-width-procent * ($index - 1));
#if ($index > 0) {
#if ($type != 'width') {
#{$type}: $column-width + $gutter + $gutter-width-procent;
} #else {
#{$type}: $column-width + $gutter;
}
}
}
I am calling that up in a different function like this:
#for $index from 1 through $column-count {
&.size-#{$index} {
#include calc-width($index, 'width');
}
}
With the variables of:
$column-count: 12 !default; //12
$row-max-width: 1024;
$gutter-width-px: 15px !default; //In px
$gutter-width-procent: percentage($gutter-width-px / $row-max-width);
I like the system. But there is one thing that doesnt seem correct...
Can i do this line on another way, then substracting from 100%?
$column-calculation: (100% - ($gutter-width-procent * ($column-count - 1))) / $column-count;
I may be getting the wrong end of the stick here but if if you used box-sizing: border-box; and padding for your gutters then you wouldn't have to do any calculation. There's a great post about border-box here.
Not really sure, if this solves your problem, but i wouldn't create the grid gutters like that. You can easily create them if you use "box-sizing", a negative margin on the parent and a padding for every column. So your ("pseudo")-HTML could look like:
.parent
.column
.column
.column
And your CSS like that:
.parent {
margin-left: -GUTTER;
}
.child {
padding-left: GUTTER;
}
Your SASS function to create the widths for the columns could then be simplified as well. I made a pen to show you one way to solve your gutter problem.
This SASS function is just for testing and doesn't check for duplicates (.size1-2 (50%) and .size2-4) and other stuff.
My maths is shocking & I cannot, for the life of me get this calculation to work. I am creating a CSS grid system that allows users to specify any number of grid columns (there are 12 by default), the gutter in between these columns, the maximum width around the columns & the margin inside that total width. The hopeful outcome is a percentage width for each column width & a percentage for the left margin of all columns.
If I use the defaults below, the max width will be 1200px, the inner margin on the left & right will be 20 giving an inner width of 1160 for the maximum allowed space for the grid. Does that make sense?
I'm using is SASS by the way. Look at the comments in the code to see what is currently working & not working.
Here is the code on jsFiddle: http://jsfiddle.net/mrmartineau/fMeBk/
$gridColumnCount : 12; // Total column count
$gridGutterWidth : 40; // [in pixels]
$gridColumnPadding : 30; // [in pixels]
$gridMaxWidth : 1200; // [in pixels]
$gridMargin : 20; // [in pixels] Space outside the grid
#function gridColumnWidth() {
#return $gridMaxWidth / $gridColumnCount;
}
// Grid calculations
#function gridColumnWidthCalc($colNumber) {
// Is correct
#if $gridGutterWidth == 0 {
#return percentage($colNumber / $gridColumnCount);
}
// Is incorrect
#else $gridMargin > 0 {
#return percentage( (($colNumber / $gridColumnCount) - gutterCalc(false) ) );
}
}
#mixin columns($columnSpan: 1) {
width: gridColumnWidthCalc($columnSpan);
}
#function gutterCalc($showUnit: true) {
#if $showUnit == true {
#return percentage( $gridGutterWidth / ( $gridMaxWidth - ($gridMargin * 2) ) );
} #else {
#return $gridGutterWidth / ( $gridMaxWidth - ($gridMargin * 2) ) * 100;
}
}
#mixin gridColumn() {
#if $gridGutterWidth > 0 {
margin-left: gutterCalc();
}
#if $gridColumnPadding > 0 {
padding: $gridColumnPadding + px;
}
float: left;
min-height: 30px;
position: relative;
clear: none;
&:first-child {
margin-left: 0;
}
background-color: pink;
border: 1px solid red;
}
#for $i from 1 to $gridColumnCount + 1 {
.span#{$i} { #include columns($i); }
}
.container {
padding-left: $gridMargin + px;
padding-right: $gridMargin + px;
max-width: $gridMaxWidth + px;
}
.col {
#include gridColumn();
}
Okay, i spent an hour to comprehend your commentless code.
First of all, there's ambiguity between "columns" as grid units and "columns" as actual elements. Below i'm calling the latter "blocks".
You are correctly overriding gutter of the first block in a row. Thus, the total number of gutters is one less than the number of blocks in a row.
But when you're calculating block widths, you're subtracting gutter from every column without taking into consideration that there are less gutters than blocks.
So you should proportionally reduce the width of a block.
Working solution:
// Accepts a number of columns that a block should span.
// Returns a percentage width for that block.
#mixin columns($columnSpan: 1) {
$number-of-blocks-in-container: $gridColumnCount / $columnSpan;
$total-width-of-all-gutters: gutterCalc(false) * ($number-of-blocks-in-container - 1);
$total-width-of-all-blocks: 1 - $total-width-of-all-gutters;
$width-of-a-single-block: $total-width-of-all-blocks / $number-of-blocks-in-container;
width: percentage( $width-of-a-single-block );
}
Now your wheel is rolling! See it in action: http://jsfiddle.net/fMeBk/46/ Keep in mind that browsers round up percentage values with a slight error, so grid positioning might be not pixel-perfect. BTW, right-aligning the last block in a row is necessary to minimize the visual effect of this rounding error.
Dude, your code architecture is so wrong, and your approach has a number of drawbacks. I can name them if you want.
You really should give Susy another try. It is a brilliant piece of SASS and also a great source to learn SASS techniques from. Its source code is well commented and available on GitHub.
According to you, what features of your grid framework does Susy lack?
I assure you, Susy can do what you want. Just explain a task and i'll try to come up with an elegant solution leveraging Susy.
PS I'm not trying to dissuade you from experimenting. Practice makes perfect! Experimenting is necessary, and you're doing a great job. What i'm trying to tell is that you should follow a good example and adopt good practices so that you don't end up in the wrong place.
PPS Please give me back my rating. I devoted a lot of my personal time trying to help you, and you minused my answer. :(
You didn't state any specific question, and that's against StackOverflow rules.
And without your explainations of the structure of your framework, it's hard to understand what exactly you're trying to achieve with each function and mixin.
How are we supposed to help?
Anyway, you're approach is faulty for two reasons:
You're trying to re-invent the wheel. There are dozens of grid frameworks already.
You're using a non-semantic approach. You're styling by applying style-specific classes in HTML. Instead, your classes should be semantic (i. e. state the function of blocks, not their look) and styling should be applied to those classes in CSS. With SASS, it's very easy.
Solution: use Susy. It's a fantastic piece of software, and its author Eric Meyer is very responsive here on StackOverflow.
With Susy, your code could look like this:
HTML:
<div id="container">
<div id="gallery">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div id="promos">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div id="footer">
<div id="bottom-menu"></div>
<div id="partners"></div>
<div id="social-buttons"></div>
</div>
<div>
<div class="col span12"></div>
</div>
</div>
SASS:
//////////
// Imports
//////////
#import susy
//////////
// Defining variables
//////////
// Main grid properties
$total-columns : 12 // Number of columns
$container-style: fluid // The grid should stretch
$max-width : 1200px // But not wider than this
// Proportions between column width and gutter between columns
$column-width : 85%
$gutter-width : 100% - $column-width
// Setting margins around the grid
$grid-padding : 1em // This will remain absolute
$container-width: 100% // If you want relative margins, change this instead
//////////
// Applying containers and columns
//////////
// Setting containers in all immediate children of #container
#container > *
+container /* ← Actual Susy magic! :D */
max-width: $max-width
// Setting columns
#gallery > *
+span-columns(1)
&:last-child // The last column should be marked with "omega"
+span-columns(1 omega) // to compensate browsers' calculation errors
#promos > *
+span-columns(2)
&:last-child
+span-columns(2 omega)
// #footer
#bottom-menu
+span-columns(6)
#partners
+span-columns(4)
#social-buttons
+span-columns(2 omega)
Sorry, i haven't tested this code, it may contain errors, but you can still see the idea.
Susy also lets you easily create responsive grids. And they say Susy is gonna be the default grid engine in Compass.
UPD: See the question-specific answer next to this one!
I put together a simple SASS percentage based grid generator a little while back. The math that you're looking for is here:
https://github.com/jordancooperman/simple_grid/blob/master/assets/css/scss/partials/_grid.scss
Some of the css in there is for display purposes only so that you will see your grid if using the markup that's also included in the project. Let me know if you have any questions, cheers!