Let's say that we have the following markup:
<section class="wrapper">
<div>column1</div>
<div>column2</div>
<div>column3</div>
<div>column4</div>
</section>
I need a mixin which will set equally the width of the columns and will float them to the left. A simple four column grid. Here is what I came up so far.
#mixin grid($columns: 2, $tag: "div") {
#{$tag} {
width: 100% / $columns;
box-sizing: border-box;
-moz-box-sizing: border-box;
float: left;
}
&:after {
display: table;
content: " ";
clear: both;
*zoom: 1;
}
}
My question is: is there any better way to do this and do I miss something.
You might want to have a look at singularitygs!
With this sass extension you can write
div {
#include grid-span(1,1,4,$output-style: 'float');
}
The parameters for grid-span are (with, startpos, context, options). All numbers will be converted to ratio-based widths. The above example can be read as:
width 1 at position 1 in a grid-context of 4
=> width: 25%; margin-left: 0;
(ouput-style: 'float' is needed, because you are targeting multiple divs)
Or you can define your base grid first, and leave out the context:
$grids: 4;
div {
#include grid-span(1,1,$output-style: 'float');
}
You can even go further and use breakpoints to have different grids for different window sizes:
$grids: 4; // base grid (mobile first)
$grids: add-grid(12 at 980px); // 12-grid for everything above 980px
$output-style: 'float'; // set the output-style globally
div {
#include grid-span(2,1); // => 50%
#include breakpoint(980px) {
#include grid-span(4,1); => 33.3333%
}
}
There is alot more possible with Singularity, so check out their wiki!
Related
I am attempting to define some default behaviors for a grid and then override them at specific breakpoints. In the following example I would like the two divs to be stacked on top of each other, with slightly modified gutter settings from the default, and then at 800px and above I would like the divs to stack next to each other. The second part does not happen. Seems like some margin settings from the less than 800px scenario are being applied to the greater than 800px scenario. Please let me know how to code this and adhere to susy best practices.
HTML:
<div class="container">
<div class="primary">
<p>I am Primary</p>
</div>
<div class="secondary">
<p>I am Secondary</p>
</div>
</div>
SCSS:
$susy:
(
flow: ltr,
output: float,
math: fluid,
column-width: false,
container: 1200px,
container-position: center,
last-flow: to, columns: 12,
gutters: 1 / 4,
gutter-position: after,
global-box-sizing: border-box,
debug: (
image: hide,
color: rgba(#66f, 0.25),
spot: background, toggle: bottom right)
);
* {
#include box-sizing(border-box);
}
.container{
#include container;
}
.primary{
background-color: red;
}
.secondary{
background-color: blue;
}
// Mobile first layout with slightly different
// gutter settings from default
#include with-layout(12 0.5 split){
.primary{
#include span(12);
}
.secondary{
#include span(12);
}
}
// this layout should take over at 800px and above
// and share a row but instead boxes end up on different
// rows
#include susy-breakpoint(800px, $susy)
{
.primary{
#include span(first 6);
}
.secondary{
#include span(last 6);
}
}
I also made a codepen example that can be found here:
http://codepen.io/sbonham/pen/vLKvMJ
Yep, Susy is just writing CSS values, so you have to handle this the same way you would with plain CSS. Susy doesn't know your DOM, so it has no way of knowing that you want to override values that you set before. If we assumed you always want to override, we would have to output massively bloated code.
There are two solutions here:
Put your small-screen layout inside a max-width media-query, so it doesn't affect larger screens.
Or: override those global values inside the large-screen media-query. The problem to fix is the extra margins added by your initial split gutters.
I prefer the first solution, because I think overrides are ugly. But if you're dealing with some small browsers that doesn't support media-queries (do those still exist?), then you'll need to use the second solution. Try:
#include susy-breakpoint(max-width 800px, 12 0.5 split) {
.primary{
#include span(12);
}
.secondary{
#include span(12);
}
}
this seems like a hack, but hopefully you get something out of this! I added the following to your codepen:
.primary, .secondary {
display: inline-block;
margin: gutter(12);
width: span(12);
width:500px;
}
http://codepen.io/alexG53090/pen/wMWNzR
I have some elements inside a DIV which get reordered depending on the size of the screen. I want to style each of these elements differently depending on their flex-box order. Because the media queries are inside a framework, I'd rather not write my own media queries to do this, because I don't want to have to remember to change my media queries if the framework changes the break points for their media queries. I tried using the + sibling selector, but apparently this only applies to the order of elements in the original markup, not the flex box rendering order. Is there any way to style an element based on the order in which it appears in the rendered DOM?
As mention in the comments, you wont be able to use nth-child, as the styles will apply to the order of the actual DOM, not the rendered DOM.
You will have to add extra classes to the markup in order to do this.
So rather than re-order using nth-child, re-order using the extra classes.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.flexGrid {
display: flex;
flex-wrap: wrap;
width: 100%;
}
.flexGrid__item {
border: 1px solid pink;
width: 50%;
height: 100px;
}
.flexGrid__item--alpha {
background: pink;
order: 1;
}
.flexGrid__item--bravo {
order: 2;
}
.flexGrid__item--charlie {
order: 3;
}
.flexGrid__item--delta {
order: 4;
}
#media screen and (min-width: 500px) {
.flexGrid__item {
width: 25%;
}
.flexGrid__item--alpha {
order: 5;
}
}
<div class="flexGrid">
<div class="flexGrid__item flexGrid__item--alpha"></div>
<div class="flexGrid__item flexGrid__item--bravo"></div>
<div class="flexGrid__item flexGrid__item--charlie"></div>
<div class="flexGrid__item flexGrid__item--delta"></div>
</div>
More detail in this fiddle:
https://jsfiddle.net/pua5u8a4/1/
I'm having a few issues understanding how to produce the following layout using Susy Next.
While this is pretty strait forward with strait CSS I can't seem to get my head around doing this cleanly in Susy, or at all really.
A caveat here is that I can't add any extra wrappers into the layout, it's just four DIV blocks and has to be that way. The other caveat is that I would really prefer to be using Susy Next (I am using alpha4 at the moment).
Really kind of hoping I am just not seeing the woods for the tress as I have only been using Susy for a few weeks.
The source order is:
first
second
third
fourth
The required layout is:
-----------------------------------------
| fourth | first |
| ----------------------------
| | second | third |
-----------------------------------------
Update 1.
Update to add my current CSS solution, I've included the markup and all the CSS taking affect on the page, for completeness:
<main>
<div class="container">
<div class="region region-first"></div>
<div class="region region-second"></div>
<div class="region region-third"></div>
<div class="region region-fourth"></div>
</div>
</main>
.container {
*zoom: 1;
max-width: 73.75em;
margin-left: auto;
margin-right: auto;
padding: 0 1.25em;
}
.container:after {
content: "";
display: table;
clear: both;
}
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
main .region:first-child {
width: 66.1016949%;
float: right;
}
main .region:nth-child(2) {
clear: right;
float: right;
margin-right: 33.8983051%;
width: 32.2033898%;
}
main .region:nth-child(3) {
margin-right: -66.1016949%;
width: 32.2033898%;
float: right;
}
main .region:last-child {
width: 32.2033898%;
margin: 0;
}
Some Ideas for a Solution?
I started to poke the internals of Susy Next and tried called the span() function directly to just get widths, hooray this works where I just need a value for width: , however...
...where I am doing margin-right: span(4 + $gutter) the margin-right value needs to be the same value as push or pre would return, but I can't quite understand all the internals of how they work, my "magical float" of .75 when calculating $gutter is ever so slightly inaccurate, it might be right, but of course change a value in set-grid and it can be wrong, so its a rough guess at best.
What I need is a way to get the same value as pre would return, but of course just the value OR just a whole better way of doing the whole thing :)
.region {
&:first-child {
#include span(8 omega of 12);
}
&:nth-child(2) {
$gutter: $gutters * .75;
margin-right: span(4 + $gutter);
width: span(4);
float: right;
clear: right;
}
&:nth-child(3) {
margin-right: - span(8);
width: span(4);
float: right;
}
&:last-child {
width: span(4);
}
}
You're right - it's totally possible and not even very hard in Susy Next:
.region {
&:first-child { #include span(last 8); }
&:nth-child(2) {
clear: right;
#include span(4 at 5 isolate);
}
&:nth-child(3) { #include span(last 4 isolate); }
&:last-child { width: span(4); }
}
The isolation option allows you to position elements at specific locations on the grid.
I will answer my own question. You will need to read through the original question as to why this is an answer - essentially what it comes down to is the right tool for the job. I was trying to solve my problem using Susy mixins (initially), however turning to Susy functions helped get me most of the way to a solution.
The final part is to write my own function to return the right value that I needed for the nth-child(2) div, it needs a margin-right to push it back into position the correct amount. Copying the internals of the Susy pre mixin was the obvious course of action here, and it worked, hooray!
#function elf-margin-value(
$span,
$columns
) {
$this: $span, $columns;
$value: if(index($this, outer), $this, append($this, outer));
#return span($value);
}
So in my code I can use it like this:
margin-right: elf-margin-value(4, 12);
Minor issue - I know what index and append are doing, but not I'm not quite sure about outer.
Not the place to discuss but I wonder if this abstraction would be good for Susy Next, rather than baking this same/similar logic into several mixins. I would benefit at least :)
Anyway this is how I solved this for now, I am still very interested to hear if Eric has some advice for this and if my solution can be done easier/better.
The solution thus far is the following:
$to: to($flow);
.region {
&:first-child {
#include span(8 omega of 12);
}
&:nth-child(2) {
margin-#{$to}: elf-margin-value(4, 12);
width: span(4);
float: $to;
clear: $to;
}
&:nth-child(3) {
margin-#{$to}: - span(8);
width: span(4);
float: $to;
}
&:last-child {
width: span(4);
}
}
I am using Suzy for partial re-design of an existing website. In stage 1, I am designing the top part of the page: header, etc. and using the legacy code for the rest.
At this point I need to fit the new headers to the old page content. Unfortunately, the usable space I end up with is smaller than the width of the existing content.
Any idea on how to adjust the content space (the width available for content placed inside the container) of #legacy-content-wrapper to be 1002px wide?
Here's my code:
$total-columns : 12; // a 12-column grid
$column-width : 69px;
$gutter-width : 14px;
$grid-padding : 25px;
$container-style: static;
// the resulting grid is 1032px wide
#header-wrapper {
#include container;
.some-header-content { #include span-columns(3,12); }
.some-other-header-content { #include span-columns(9 omega,12); }
}
#page-wrapper {
#include container;
// legacy item, needs to be 1002px wide!
#legacy-content-wrapper {
#include span-columns(12 omega, 12);
// my children will be 982px at 100% width
// #include bleed($gutter-width) changes the width of the container
// but does not change the size of the usable space within it.
// how can I modify this item to have content swidth of 1002px?
}
}
This is what I am looking for:
<div id="page-wrapper">
<div id="legacy-content-wrapper">
<div>I'd like to be 1002 pixels wide!</div>
</div>
</div>
I ended up with:
#legacy-content-wrapper {
margin: 0 0 -$grid-padding;
padding: 22px 14px;
#include clearfix;
}
You can adjust any of the grid settings to fit within the required space. Probably the most straightforward way to trim 30px off your grid size would be from the grid-padding setting.
$total-columns : 12;
$column-width : 69px;
$gutter-width : 14px;
$grid-padding : 10px;
$container-style: static;
You could alternatively tweak the column-width or gutter-width settings to achieve the same number. It's hard to say the best approach without seeing the design. Either way should get you to 1002px.
I just started to play with Susy. I have a 12 column grid that has grid-padding on it. Now i want the header of my page to span the whole grid including the grid-padding. What I'm doing right now is calculating the overall width and then setting a negative margin on the header. That's feels rather hacky to me... Is there a cleaner way to do it?
$total-columns : 12;
$column-width : 3.5em;
$gutter-width : 1.25em;
$grid-padding : 2em;
$total-width: ( $total-columns * ($column-width + $gutter-width) ) + ( 2 * $grid-padding ) - $gutter-width;
header {
height: 150px;
width: $total-width;
margin-left: -$grid-padding;
}
You have two good options. One is a simplified version of what you have. Since block elements are 100% width by default, you can simply eliminate your width setting (and all that hacky math).
header {
height: 150px;
margin: 0 0 - $grid-padding;
}
Your other option is to use multiple containers on the page. That requires a change to the markup, but sometimes it's a simplification that works well. If you move the header outside your current container, and declare it as a container of it's own, that will do the trick.
(as a side note: if you do need the full width ever, you can simply use the columns-width() function (for inner width, without padding) or container-outer-width() for the full width including the padding.)
UPDATE:
I've been using this mixin, to apply bleed anywhere I need it:
#mixin bleed($padding: $grid-padding, $sides: left right) {
#if $sides == 'all' {
margin: - $padding;
padding: $padding;
} #else {
#each $side in $sides {
margin-#{$side}: - $padding;
padding-#{$side}: $padding;
}
}
}
Some examples:
#header { #include bleed; }
#nav { #include bleed($sides: left); }
#main { #include bleed($sides: right); }
#footer { #include bleed(space(3)); }