├── .gitignore ├── README.md ├── rebar.scss ├── rebar.styl └── test ├── Sass ├── desktop-first.scss └── mobile-first.scss ├── Stylus ├── desktop-first.styl └── mobile-first.styl └── test.html /.gitignore: -------------------------------------------------------------------------------- 1 | .sass-cache 2 | *.map 3 | *.css 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Rebar Grid Framework 3 | 4 | Rebar is aimed to make responsive development more efficient and keep CSS organised. The idea is to setup a list of breakpoints and assign container or grid settings for each breakpoint at one time. It use `padding` for gutter, works the same way as Bootstrap 3 grid system does. So if you already familiar with Bootstrap, you will find Rebar is easy to use and far more flexible. 5 | 6 | Rebar requires Sass 3.4 or Stylus and is incompatible with Libsass 3.1. 7 | 8 | Please read the [Guide](http://rebar.io/guide.html) to learn more about Rebar, or read the [Settings](http://rebar.io/settings.html) to check out all available settings.
9 | 10 | 中文说明请查阅 [http://peiwen.lu/2015/rebar-grid-framework](http://peiwen.lu/2015/rebar-grid-framework) 11 | 12 | ## Copyright & License 13 | 14 | Copyright (c) 2015 Peiwen Lu - Released under the MIT license. 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy 17 | of this software and associated documentation files (the "Software"), to deal 18 | in the Software without restriction, including without limitation the rights 19 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 | copies of the Software, and to permit persons to whom the Software is 21 | furnished to do so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in 24 | all copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32 | THE SOFTWARE. 33 | -------------------------------------------------------------------------------- /rebar.scss: -------------------------------------------------------------------------------- 1 | 2 | // Rebar Grid Framework v1.0.0 3 | // Copyright (c) 2015 Peiwen Lu 4 | // Released under the MIT License. 5 | 6 | 7 | //------- DEFAULT SETTINGS -------// 8 | 9 | $mobile-first : true !default; 10 | $max-width : 1170px !default; 11 | $breakpoints : if($mobile-first, 481px 769px 993px, 992px 768px 480px) !default; 12 | $gutters : if($mobile-first, 20px 20px 26px 30px, 30px 26px 20px 20px) !default; 13 | 14 | // Collect containers which have gutters. These containers will be generated together with $grid-gutter-list. 15 | $container-gutter-list: (); 16 | 17 | 18 | 19 | //------- FUNCITONS -------// 20 | 21 | // # CONVERT FRACTION TO PERCENTAGE 22 | @function to-percentage($n) { 23 | @if $n { 24 | @return if(unitless($n), percentage($n), $n); 25 | } @else { 26 | @return $n; 27 | } 28 | } 29 | 30 | 31 | // # QUERY VALUE 32 | // Query value for target slice. 33 | // If there's no value, return `false` as default value. 34 | @function query-value($map, $key, $bk) { 35 | $list: map-get($map, $key); 36 | @return if(length($list) >= $bk, nth($list, $bk), false); 37 | } 38 | 39 | 40 | // # MEDIA FEATURE 41 | // Output media feature for `slicer()` mixin. 42 | @function media-feature($bk) { 43 | @if $mobile-first { 44 | @return if($bk > 0, min-width, max-width); 45 | } @else { 46 | @return if($bk > 0, max-width, min-width); 47 | } 48 | } 49 | 50 | // # QUERY BREAKPOINT WIDTH 51 | // Query breakpoint width for `slicer()` mixin. 52 | // If negative slice index, minus 1 (if $mobile-first: true) or plus 1 (if $mobile-first: false). 53 | @function query-breakpoint($bk) { 54 | @if $bk > 0 { 55 | @return nth($breakpoints, $bk); 56 | } @else if $bk < 0 { 57 | @return nth($breakpoints, abs($bk)) + if($mobile-first, -1, 1); 58 | } 59 | } 60 | 61 | 62 | // # QUERY CONTAINER SETTINGS 63 | // Generate a comma separated list contains several space separated lists. 64 | // Each sub-list represents a container and contains the settings of target slice. 65 | 66 | // * $selector -> selector name 67 | // * $nested -> enable minus margin 68 | // * $new-max-width -> override default $max-width 69 | // * $min-width -> min-width 70 | // * $width -> width 71 | @function query-container($bk) { 72 | $list: (); 73 | 74 | @for $i from 1 through length($container) { 75 | $selector: nth(map-keys($container), $i); 76 | $nested: false; 77 | $new-max-width: false; 78 | $min-width: false; 79 | $width: false; 80 | 81 | $entry: map-get($container, $selector); 82 | 83 | @if map-get($entry, nested) == true { 84 | $nested: true; 85 | } 86 | 87 | // Only query max-width and min-width at the first slice. 88 | @if $bk == 1 { 89 | $new-max-width-value: map-get($entry, max-width); 90 | @if $new-max-width-value and length($new-max-width-value) == 1 { 91 | $new-max-width: to-percentage($new-max-width-value); 92 | } 93 | 94 | $min-width-value: map-get($entry, min-width); 95 | @if $min-width-value and length($min-width-value) == 1 { 96 | $min-width: to-percentage($min-width-value); 97 | } 98 | } 99 | 100 | @if map-has-key($entry, width) { 101 | $width: to-percentage(query-value($entry, width, $bk)); 102 | } 103 | 104 | // If container has gutter, add its selector to $container-gutter-list. 105 | @if map-get($entry, gutter) == true { 106 | $container-gutter-list: append($container-gutter-list, $selector, comma) !global; 107 | } 108 | 109 | $value: join($selector, $nested $new-max-width $min-width $width); 110 | $list: append($list, $value, comma); 111 | } 112 | 113 | @return $list; 114 | } 115 | 116 | 117 | // # QUERY GRID SETTINGS 118 | // Generate a comma separated list contains several space separated lists. 119 | // Each sub-list represents a grid and contains the settings of target slice. 120 | // 121 | // * $selector -> selector name 122 | // * $float -> float 123 | // * $offset-left -> margin-left 124 | // * $offset-right -> margin-right 125 | // * $gutter-left -> padding-left 126 | // * $gutter-right -> padding-right 127 | // * $max-width -> max-width 128 | // * $width -> width 129 | // * $container -> disable padding 130 | // * $offset-only -> only has margin, disable other settings 131 | @function query-grid($bk) { 132 | $list: (); 133 | 134 | @for $i from 1 through length($grid) { 135 | $selector: nth(map-keys($grid), $i); 136 | $entry: map-get($grid, $selector); 137 | $value: $selector; 138 | 139 | @if map-has-key($entry, float) { 140 | $value: append($value, query-value($entry, float, $bk)); 141 | } @else { 142 | $value: append($value, false); 143 | } 144 | 145 | @each $key in (offset-left, offset-right, gutter-left, gutter-right, max-width, width) { 146 | @if map-has-key($entry, $key) { 147 | $value: append($value, to-percentage(query-value($entry, $key, $bk))); 148 | } @else { 149 | $value: append($value, false); 150 | } 151 | } 152 | 153 | @if map-get($entry, container) == true { 154 | $value: append($value, true); 155 | } @else { 156 | $value: append($value, false); 157 | } 158 | 159 | // If grid only has offset settings, set $offset-only `true`. 160 | @if ( (length($entry) == 1) and (map-has-key($entry, offset-left) or (map-has-key($entry, offset-right))) ) 161 | or ( (length($entry) == 2) and (map-has-key($entry, offset-left) and (map-has-key($entry, offset-right))) ) { 162 | $value: append($value, true); 163 | } @else { 164 | $value: append($value, false); 165 | } 166 | 167 | $list: append($list, $value, comma); 168 | } 169 | 170 | @return $list; 171 | } 172 | 173 | 174 | 175 | //------- MIXINS -------// 176 | 177 | // # CONTAINER MIXIN 178 | // Generate containers code for target slice. 179 | @mixin container($bk) { 180 | $container: query-container($bk); 181 | $gutter: to-percentage(nth($gutters, $bk)/2); 182 | $container-list: (); 183 | 184 | // @debug $container; 185 | 186 | @each $selector, $nested, $new-max-width, $min-width, $width in $container { 187 | #{$selector} { 188 | @if $bk == 1 { 189 | @if $nested { 190 | margin-left: - $gutter; 191 | margin-right: - $gutter; 192 | } @else { 193 | margin-left: auto; 194 | margin-right: auto; 195 | 196 | @if $new-max-width { 197 | max-width: $new-max-width; 198 | } @else { 199 | max-width: to-percentage($max-width); 200 | } 201 | 202 | @if $min-width { 203 | min-width: $min-width; 204 | } 205 | 206 | @if $width { 207 | width: $width; 208 | } 209 | } 210 | 211 | $container-list: append($container-list, $selector, comma); 212 | 213 | } @else { 214 | @if $nested { 215 | margin-left: - $gutter; 216 | margin-right: - $gutter; 217 | } @else if $width { 218 | width: $width; 219 | } 220 | } 221 | } 222 | } 223 | 224 | // Clearfix 225 | @if $bk == 1 { 226 | #{$container-list} { 227 | &:after { 228 | content: ""; 229 | display: table; 230 | clear: both; 231 | } 232 | } 233 | } 234 | 235 | } 236 | 237 | 238 | // # GRID MIXIN 239 | // Generate grids code for target slice. 240 | @mixin grid($bk) { 241 | $grid: query-grid($bk); 242 | $gutter: to-percentage(nth($gutters, $bk)/2); 243 | $grid-gutter-list: (); 244 | $full-width-list: (); 245 | 246 | // @debug $grid; 247 | 248 | @each $selector, $float, $offset-left, $offset-right, $gutter-left, $gutter-right, $grid-max-width, $width, $container, $offset-only in $grid { 249 | 250 | #{$selector} { 251 | // $offset-only grid doesn't have float property. 252 | @if $bk == 1 and not $offset-only { 253 | float: if($float, $float, left); 254 | 255 | @if $grid-max-width { 256 | max-width: $grid-max-width; 257 | width: 100%; 258 | } 259 | } @else if $float { 260 | float: $float; 261 | } 262 | 263 | @if $offset-left { 264 | margin-left: $offset-left; 265 | } 266 | @if $offset-right { 267 | margin-right: $offset-right; 268 | } 269 | 270 | // $container grid doesn't have padding property. 271 | @if not $container { 272 | @if $gutter-left and $gutter-right { 273 | padding-left: $gutter-left; 274 | padding-right: $gutter-right; 275 | } @else if $gutter-left { 276 | padding-left: $gutter-left; 277 | padding-right: $gutter; 278 | } @else if $gutter-right { 279 | padding-left: $gutter; 280 | padding-right: $gutter-right; 281 | } @else if not $offset-only { 282 | // Add grid which has default gutter to $grid-gutter-list. 283 | $grid-gutter-list: append($grid-gutter-list, $selector, comma); 284 | } 285 | } 286 | 287 | // Add grid which has 100% width to $full-width-list. 288 | @if $width and $width == 100% { 289 | $full-width-list: append($full-width-list, $selector, comma); 290 | } @else if $width { 291 | width: $width; 292 | } 293 | } 294 | } 295 | 296 | // Generate all grids and containers which have default gutter together. 297 | @if $container-gutter-list != () or $grid-gutter-list != () { 298 | #{join($container-gutter-list, $grid-gutter-list, comma)} { 299 | padding-left: $gutter; 300 | padding-right: $gutter; 301 | } 302 | // Clear $container-gutter-list at each breakpoint. 303 | $container-gutter-list: () !global; 304 | } 305 | 306 | // Generate $full-width-list. 307 | @if $full-width-list != () { 308 | #{$full-width-list} { 309 | width: 100%; 310 | } 311 | } 312 | } 313 | 314 | 315 | // # SLICER MIXIN 316 | @mixin slicer($bk...) { 317 | @if length($bk) == 1 { 318 | $a: nth($bk, 1); 319 | @media screen and (media-feature($a): query-breakpoint($a)) { 320 | @content; 321 | } 322 | } @else if length($bk) == 2 { 323 | $a: nth($bk, 1); 324 | $b: nth($bk, 2); 325 | @media screen and (media-feature($a): query-breakpoint($a)) 326 | and (media-feature($b): query-breakpoint($b)) { 327 | @content; 328 | } 329 | } 330 | } 331 | 332 | 333 | //------- OUTPUT -------// 334 | 335 | @include container(1); 336 | @include grid(1); 337 | 338 | @for $bk from 1 through length($breakpoints) { 339 | // $breakpoints length is 1 shorter than $gutters. Add 1 for querying value. 340 | // Do not add 1 for `slicer()` mixin so keep responsive slice index start from 0. 341 | @include slicer($bk) { 342 | @include container($bk + 1); 343 | @include grid($bk + 1); 344 | } 345 | } 346 | -------------------------------------------------------------------------------- /rebar.styl: -------------------------------------------------------------------------------- 1 | 2 | // Rebar Grid Framework v1.0.0 3 | // Copyright (c) 2015 Peiwen Lu 4 | // Released under the MIT License. 5 | 6 | 7 | //------- DEFAULT SETTINGS -------// 8 | 9 | $mobile-first ?= true 10 | $max-width ?= 1170px 11 | $breakpoints ?= $mobile-first ? 481px 769px 993px : 992px 768px 480px 12 | $gutters ?= $mobile-first ? 20px 20px 26px 30px : 30px 26px 20px 20px 13 | 14 | // Collect containers which have gutters. These containers will be generated together with grid-gutter-list. 15 | $container-gutter-list = () 16 | 17 | 18 | 19 | //------- FUNCITONS -------// 20 | 21 | // # CONVERT FRACTION TO PERCENTAGE 22 | to-percentage(n) 23 | if type(n) == 'unit' 24 | return unit(n) ? n : n * 100% 25 | else 26 | return n 27 | 28 | 29 | // # MEDIA FEATURE 30 | // Output media feature for `slicer()` mixin. 31 | media-feature(bk) 32 | if $mobile-first 33 | return bk > 0 ? min-width : max-width 34 | else 35 | return bk > 0 ? max-width : min-width 36 | 37 | 38 | // # QUERY BREAKPOINT WIDTH 39 | // Query breakpoint width for `slicer()` mixin. 40 | // If negative slice index, minus 1 (if $mobile-first: true) or plus 1 (if $mobile-first: false). 41 | query-breakpoint(bk) 42 | if bk > 0 43 | return $breakpoints[bk - 1] 44 | else if bk < 0 45 | return $breakpoints[abs(bk + 1)] + ($mobile-first ? - 1 : 1) 46 | 47 | 48 | // # QUERY CONTAINER SETTINGS 49 | // Generate a comma separated list contains several space separated lists. 50 | // Each sub-list represents a container and contains the settings of target slice. 51 | 52 | // * i0 -> selector -> selector name 53 | // * i1 -> nested -> enable minus margin 54 | // * i2 -> max-width -> override default $max-width 55 | // * i3 -> min-width -> min-width 56 | // * i4 -> width -> width 57 | query-container(bk) 58 | list = () 59 | 60 | for i0 in $container 61 | entry = $container[i0] 62 | 63 | i0 = join('', split(' ', i0)) // Remove space between selectors. 64 | i1 = entry.nested == true ? true : null 65 | i2 = entry.max-width && length(entry.max-width) == 1 ? to-percentage(entry.max-width) : null 66 | i3 = entry.min-width && length(entry.min-width) == 1 ? to-percentage(entry.min-width) : null 67 | i4 = entry.width ? to-percentage(entry.width[bk]) : null 68 | 69 | if entry.gutter == true 70 | push($container-gutter-list, i0 + ', ') 71 | 72 | entry = join(' ', i0 i1 i2 i3 i4) 73 | push(list, entry) 74 | // end for 75 | return list 76 | 77 | 78 | // # QUERY GRID SETTINGS 79 | // Generate a comma separated list contains several space separated lists. 80 | // Each sub-list represents a grid and contains the settings of target slice. 81 | // 82 | // * i0 -> selector -> selector name 83 | // * i1 -> float -> float 84 | // * i2 -> offset-left -> margin-left 85 | // * i3 -> offset-right -> margin-right 86 | // * i4 -> gutter-left -> padding-left 87 | // * i5 -> gutter-right -> padding-right 88 | // * i6 -> max-width -> max-width 89 | // * i7 -> width -> width 90 | // * i8 -> container -> disable padding 91 | // * i9 -> offset-only -> only has margin, disable other settings 92 | query-grid(bk) 93 | list = () 94 | 95 | for i0 in $grid 96 | entry = $grid[i0] 97 | 98 | i0 = join('', split(' ', i0)) // Remove space between selectors. 99 | i1 = entry.float ? entry.float[bk] : null 100 | i2 = entry.offset-left ? to-percentage(entry.offset-left[bk]) : null 101 | i3 = entry.offset-right ? to-percentage(entry.offset-right[bk]) : null 102 | i4 = entry.gutter-left ? to-percentage(entry.gutter-left[bk]) : null 103 | i5 = entry.gutter-right ? to-percentage(entry.gutter-right[bk]) : null 104 | i6 = entry.max-width ? to-percentage(entry.max-width[bk]) : null 105 | i7 = entry.width ? to-percentage(entry.width[bk]) : null 106 | i8 = entry.container == true ? true : null 107 | i9 = entry.float == null && entry.gutter-left == null && entry.gutter-right == null && entry.max-width == null && entry.width == null ? true : null 108 | 109 | entry = join(' ', i0 i1 i2 i3 i4 i5 i6 i7 i8 i9) 110 | push(list, entry) 111 | // end for 112 | return list 113 | 114 | 115 | 116 | //------- MIXINS -------// 117 | 118 | // # CONTAINER MIXIN 119 | // Generate containers code for target slice. 120 | container(bk) 121 | container = query-container(bk) 122 | gutter = to-percentage($gutters[bk]/2) 123 | container-list = () 124 | 125 | for i in container 126 | i = split(' ', i) 127 | 128 | selector = i[0] 129 | nested = i[1] == 'true' 130 | max-width = i[2] == 'null' ? false : unquote(i[2]) 131 | min-width = i[3] == 'null' ? false : unquote(i[3]) 132 | width = i[4] == 'null' ? false : unquote(i[4]) 133 | 134 | {selector} 135 | // First slice 136 | if !bk 137 | if nested 138 | margin-left: - gutter 139 | margin-right: - gutter 140 | else 141 | margin-left: auto 142 | margin-right: auto 143 | 144 | if max-width 145 | max-width: max-width 146 | else 147 | max-width: to-percentage($max-width) 148 | 149 | if min-width 150 | min-width: min-width 151 | 152 | if width 153 | width: width 154 | 155 | push(container-list, selector) 156 | 157 | // other slices 158 | else 159 | if nested 160 | margin-left: - gutter 161 | margin-right: - gutter 162 | else if width 163 | width: width 164 | // end for 165 | 166 | // Clearfix 167 | if !bk 168 | {join(', ', container-list)} 169 | &:after 170 | content: "" 171 | display: table 172 | clear: both 173 | 174 | 175 | // # GRID MIXIN 176 | // Generate grids code for target slice. 177 | grid(bk) 178 | grid = query-grid(bk) 179 | gutter = to-percentage($gutters[bk]/2) 180 | grid-gutter-list = () 181 | full-width-list = () 182 | 183 | for i in grid 184 | i = split(' ', i) 185 | 186 | selector = i[0] 187 | float = i[1] == 'null' ? false : unquote(i[1]) 188 | offset-left = i[2] == 'null' ? false : unquote(i[2]) 189 | offset-right = i[3] == 'null' ? false : unquote(i[3]) 190 | gutter-left = i[4] == 'null' ? false : unquote(i[4]) 191 | gutter-right = i[5] == 'null' ? false : unquote(i[5]) 192 | max-width = i[6] == 'null' ? false : unquote(i[6]) 193 | width = i[7] == 'null' ? false : unquote(i[7]) 194 | container = i[8] == 'true' 195 | offset-only = i[9] == 'true' 196 | 197 | {selector} 198 | if !bk && !offset-only 199 | // offset-only grid doesn't have float property. 200 | float: float ? float : left 201 | if max-width 202 | max-width: max-width 203 | width: 100% 204 | else if float 205 | float: float 206 | 207 | if offset-left 208 | margin-left: offset-left 209 | if offset-right 210 | margin-right: offset-right 211 | 212 | // container grid doesn't have padding property. 213 | if !container 214 | if gutter-left && gutter-right 215 | padding-left: gutter-left 216 | padding-right: gutter-right 217 | else if gutter-left 218 | padding-left: gutter-left 219 | padding-right: gutter 220 | else if gutter-right 221 | padding-left: gutter 222 | padding-right: gutter-right 223 | else if !offset-only 224 | // Add grid which has default gutter to grid-gutter-list. 225 | push(grid-gutter-list, selector + ', ') 226 | 227 | // Add grid which has 100% width to full-width-list. 228 | if width == '100%' 229 | push(full-width-list, selector) 230 | else if width 231 | width: width 232 | // end for 233 | 234 | 235 | // Generate all grids and containers which have default gutter together. 236 | if $container-gutter-list || grid-gutter-list 237 | {join(', ', $container-gutter-list grid-gutter-list)} 238 | padding-left: gutter 239 | padding-right: gutter 240 | // Clear container-gutter-list at each breakpoint. 241 | $container-gutter-list = () 242 | 243 | // Generate full-width-list. 244 | if full-width-list 245 | {join(', ', full-width-list)} 246 | width: 100% 247 | 248 | 249 | // # SLICER MIXIN 250 | slicer(bk...) 251 | if length(bk) == 1 252 | @media screen and ({media-feature(bk[0])}: query-breakpoint(bk[0])) 253 | {block} 254 | else if length(bk) == 2 255 | @media screen and ({media-feature(bk[0])}: query-breakpoint(bk[0])) and ({media-feature(bk[1])}: query-breakpoint(bk[1])) 256 | {block} 257 | 258 | 259 | //------- OUTPUT -------// 260 | 261 | container(0) 262 | grid(0) 263 | 264 | for bk in 1..length($breakpoints) 265 | +slicer(bk) 266 | container(bk) 267 | grid(bk) 268 | -------------------------------------------------------------------------------- /test/Sass/desktop-first.scss: -------------------------------------------------------------------------------- 1 | 2 | $mobile-first: false; 3 | 4 | // # Containers 5 | $container: ( 6 | ".container": (), 7 | ".container-gutter": (gutter: true), 8 | ".container-nested": (nested: true), 9 | ".container-width": (width: 900px 600px 300px 100px), 10 | ".container-max-width": (max-width: 1280px), 11 | ".container-min-width": (min-width: 600px) 12 | ); 13 | 14 | // # Grids 15 | $grid: ( 16 | ".grid-float": ( 17 | width: 1/3, 18 | float: right left null right 19 | ), 20 | ".grid-offset-left": ( 21 | width: 1/2, 22 | offset-left: 1/4 30px 0 23 | ), 24 | ".grid-offset-right": ( 25 | width: 1/2, 26 | float: right, 27 | offset-right: 1/4 30px 0 28 | ), 29 | ".grid-gutter-left": ( 30 | width: 1/2, 31 | gutter-left: 30px 5% null 0 32 | ), 33 | ".grid-gutter-right": ( 34 | width: 1/2, 35 | gutter-right: 30px .05 null 0 36 | ), 37 | ".grid-width": ( 38 | width: 1/4 .5 1 39 | ), 40 | ".grid-max-width": ( 41 | max-width: 800px 42 | ), 43 | ".grid-container": ( 44 | width: 2/3, 45 | container: true 46 | ), 47 | 48 | 49 | ".grid-offset-only": ( 50 | offset-left: 1/3 30px 0 51 | ), 52 | ".more, .than, .one, .selectors": ( 53 | width: 1/2 54 | ) 55 | ); 56 | 57 | @import '../../rebar.scss'; 58 | 59 | /* slicer */ 60 | 61 | body { 62 | @include slicer(-1) { 63 | opacity: 1; 64 | } 65 | @include slicer(1) { 66 | opacity: 1; 67 | &:before { 68 | content: "slice 1"; 69 | } 70 | } 71 | @include slicer(-2) { 72 | opacity: 1; 73 | } 74 | @include slicer(2) { 75 | opacity: 1; 76 | &:before { 77 | content: "slice 2"; 78 | } 79 | } 80 | @include slicer(-3) { 81 | opacity: 1; 82 | } 83 | @include slicer(3) { 84 | opacity: 1; 85 | &:before { 86 | content: "slice 3"; 87 | } 88 | } 89 | @include slicer(1, -2) { 90 | opacity: 1; 91 | } 92 | @include slicer(2, -3) { 93 | opacity: 1; 94 | } 95 | @include slicer(1, -3) { 96 | opacity: 1; 97 | } 98 | } 99 | 100 | @media screen and (max-device-width: query-breakpoint(1)) and (min-device-width: query-breakpoint(-3)) { 101 | body { 102 | opacity: 1; 103 | } 104 | } 105 | 106 | 107 | #css:after { 108 | content: 'Sass desktop first' 109 | } 110 | -------------------------------------------------------------------------------- /test/Sass/mobile-first.scss: -------------------------------------------------------------------------------- 1 | 2 | // # Containers 3 | $container: ( 4 | ".container": (), 5 | ".container-gutter": (gutter: true), 6 | ".container-nested": (nested: true), 7 | ".container-width": (width: 100px 300px 600px 900px), 8 | ".container-max-width": (max-width: 1280px), 9 | ".container-min-width": (min-width: 600px) 10 | ); 11 | 12 | // # Grids 13 | $grid: ( 14 | ".grid-float": ( 15 | width: 1/3, 16 | float: right left null right 17 | ), 18 | ".grid-offset-left": ( 19 | width: 1/2, 20 | offset-left: 0 null 30px 1/4 21 | ), 22 | ".grid-offset-right": ( 23 | width: 1/2, 24 | float: right, 25 | offset-right: 0 null 30px 1/4 26 | ), 27 | ".grid-gutter-left": ( 28 | width: 1/2, 29 | gutter-left: 0 null 5% 30px 30 | ), 31 | ".grid-gutter-right": ( 32 | width: 1/2, 33 | gutter-right: 0 null .05 30px 34 | ), 35 | ".grid-width": ( 36 | width: 1 null .5 1/4 37 | ), 38 | ".grid-max-width": ( 39 | max-width: 800px 40 | ), 41 | ".grid-container": ( 42 | width: 2/3, 43 | container: true 44 | ), 45 | 46 | 47 | ".grid-offset-only": ( 48 | offset-left: 0 null 30px 1/3 49 | ), 50 | ".more, .than, .one, .selectors": ( 51 | width: 1/2 52 | ) 53 | ); 54 | 55 | @import '../../rebar.scss'; 56 | 57 | /* slicer */ 58 | 59 | body { 60 | @include slicer(-1) { 61 | opacity: 1; 62 | } 63 | @include slicer(1) { 64 | opacity: 1; 65 | &:before { 66 | content: "slice 1"; 67 | } 68 | } 69 | @include slicer(-2) { 70 | opacity: 1; 71 | } 72 | @include slicer(2) { 73 | opacity: 1; 74 | &:before { 75 | content: "slice 2"; 76 | } 77 | } 78 | @include slicer(-3) { 79 | opacity: 1; 80 | } 81 | @include slicer(3) { 82 | opacity: 1; 83 | &:before { 84 | content: "slice 3"; 85 | } 86 | } 87 | @include slicer(1, -2) { 88 | opacity: 1; 89 | } 90 | @include slicer(2, -3) { 91 | opacity: 1; 92 | } 93 | @include slicer(1, -3) { 94 | opacity: 1; 95 | } 96 | } 97 | 98 | @media screen and (min-device-width: query-breakpoint(1)) and (max-device-width: query-breakpoint(-3)) { 99 | body { 100 | opacity: 1; 101 | } 102 | } 103 | 104 | 105 | #css:after { 106 | content: 'Sass mobile first' 107 | } 108 | -------------------------------------------------------------------------------- /test/Stylus/desktop-first.styl: -------------------------------------------------------------------------------- 1 | 2 | $mobile-first = false; 3 | 4 | // # Containers 5 | $container = { 6 | ".container": {}, 7 | ".container-gutter": {gutter: true}, 8 | ".container-nested": {nested: true}, 9 | ".container-width": {width: 900px 600px 300px 100px}, 10 | ".container-max-width": {max-width: 1280px}, 11 | ".container-min-width": {min-width: 600px} 12 | }; 13 | 14 | // # Grids 15 | $grid = { 16 | ".grid-float": { 17 | width: 1/3, 18 | float: right left null right 19 | }, 20 | ".grid-offset-left": { 21 | width: 1/2, 22 | offset-left: 1/4 30px 0 23 | }, 24 | ".grid-offset-right": { 25 | width: 1/2, 26 | float: right, 27 | offset-right: 1/4 30px 0 28 | }, 29 | ".grid-gutter-left": { 30 | width: 1/2, 31 | gutter-left: 30px 5% null 0 32 | }, 33 | ".grid-gutter-right": { 34 | width: 1/2, 35 | gutter-right: 30px .05 null 0 36 | }, 37 | ".grid-width": { 38 | width: 1/4 .5 1 39 | }, 40 | ".grid-max-width": { 41 | max-width: 800px 42 | }, 43 | ".grid-container": { 44 | width: 2/3, 45 | container: true 46 | }, 47 | 48 | 49 | ".grid-offset-only": { 50 | offset-left: 1/3 30px 0 51 | }, 52 | ".more, .than, .one, .selectors": { 53 | width: 1/2 54 | } 55 | }; 56 | 57 | @import '../../rebar.styl'; 58 | 59 | /* slicer */ 60 | 61 | body 62 | +slicer(-1) 63 | opacity 1 64 | +slicer(1) 65 | opacity 1 66 | &:before 67 | content "slice 1" 68 | +slicer(-2) 69 | opacity 1 70 | +slicer(2) 71 | opacity 1 72 | &:before 73 | content "slice 2" 74 | +slicer(-3) 75 | opacity 1 76 | +slicer(3) 77 | opacity 1 78 | &:before 79 | content "slice 3" 80 | +slicer(1, -2) 81 | opacity 1 82 | +slicer(2, -3) 83 | opacity 1 84 | +slicer(1, -3) 85 | opacity 1 86 | 87 | @media screen and (max-device-width: query-breakpoint(1)) and (min-device-width: query-breakpoint(-3)) 88 | body 89 | opacity 1 90 | 91 | 92 | #css:after 93 | content: 'Stylus desktop first' 94 | -------------------------------------------------------------------------------- /test/Stylus/mobile-first.styl: -------------------------------------------------------------------------------- 1 | 2 | // # Containers 3 | $container = { 4 | ".container": {}, 5 | ".container-gutter": {gutter: true}, 6 | ".container-nested": {nested: true}, 7 | ".container-width": {width: 100px 300px 600px 900px}, 8 | ".container-max-width": {max-width: 1280px}, 9 | ".container-min-width": {min-width: 600px} 10 | }; 11 | 12 | // # Grids 13 | $grid = { 14 | ".grid-float": { 15 | width: 1/3, 16 | float: right left null right 17 | }, 18 | ".grid-offset-left": { 19 | width: 1/2, 20 | offset-left: 0 null 30px 1/4 21 | }, 22 | ".grid-offset-right": { 23 | width: 1/2, 24 | float: right, 25 | offset-right: 0 null 30px 1/4 26 | }, 27 | ".grid-gutter-left": { 28 | width: 1/2, 29 | gutter-left: 0 null 5% 30px 30 | }, 31 | ".grid-gutter-right": { 32 | width: 1/2, 33 | gutter-right: 0 null .05 30px 34 | }, 35 | ".grid-width": { 36 | width: 1 null .5 1/4 37 | }, 38 | ".grid-max-width": { 39 | max-width: 800px 40 | }, 41 | ".grid-container": { 42 | width: 2/3, 43 | container: true 44 | }, 45 | 46 | 47 | ".grid-offset-only": { 48 | offset-left: 0 null 30px 1/3 49 | }, 50 | ".more, .than, .one, .selectors": { 51 | width: 1/2 52 | } 53 | }; 54 | 55 | @import '../../rebar.styl'; 56 | 57 | /* slicer */ 58 | 59 | body 60 | +slicer(-1) 61 | opacity 1 62 | +slicer(1) 63 | opacity 1 64 | &:before 65 | content "slice 1" 66 | +slicer(-2) 67 | opacity 1 68 | +slicer(2) 69 | opacity 1 70 | &:before 71 | content "slice 2" 72 | +slicer(-3) 73 | opacity 1 74 | +slicer(3) 75 | opacity 1 76 | &:before 77 | content "slice 3" 78 | +slicer(1, -2) 79 | opacity 1 80 | +slicer(2, -3) 81 | opacity 1 82 | +slicer(1, -3) 83 | opacity 1 84 | 85 | @media screen and (min-device-width: query-breakpoint(1)) and (max-device-width: query-breakpoint(-3)) 86 | body 87 | opacity 1 88 | 89 | 90 | #css:after 91 | content: 'Stylus mobile first' 92 | -------------------------------------------------------------------------------- /test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |