Skip to content

Instantly share code, notes, and snippets.

@scottkellum
Forked from mirisuzanne/about.md
Last active December 10, 2015 00:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scottkellum/4352403 to your computer and use it in GitHub Desktop.
Save scottkellum/4352403 to your computer and use it in GitHub Desktop.

About This Proposal

This is a very rough proposal for a radical Susy 2.0 API overhaul.

The basic goals are:

  1. Flexible: Allow all the main layout approaches.
  • float / isolation
  • columns (symmetrical & asymmetrical) / fractions / explicit widths
  • gutters inside or outside - before, after, or split
  1. Simple: Less API is better.
  • Less universal settings, everything can be controlled on-the-fly when possible
  • Less mixins, with more power and flexibility
  1. Moving Forward: Backwards functionality should be maintained.
  • Anything you created in Susy 1.0 can be recreated in 2.0
  • Layouts created in 1.0 do not need to work in 2.0 automatically
  1. Light Touch: Always do the minimum possible to achieve a layout.
  • If there's a question, less output is the answer.
  1. Prepared: Plan ahead for flexbox & grid modules. (not considered yet in this proposal)

(Changes inspired largely by Singularity and Salsa, with elements from Zen as well.)

// ----------------------------------------------------------------------------
// Settings
// $grid : [<number> <settings> | <width> <complex-layout>] [inside | outside] [before | after | split];
// $direction : [left to right | right to left];
// Example: The current Susy default.
$grid : 12 4em 1em 1em outside after;
// Example: The current Singularity demo.
$grid : (1 2 3 5 2 3) .25;
// Example: The current Salsa default.
$grid : 16 auto 20px inside split;
// ----------------------------------------------------------------------------
// Grid Container
//
// @include grid($width...)
// - $width : <breakpoint> [static] <arbitrary with | column math>;
// : 12 4em 1.5em - Column math (explicit)
// : 12 4em 1.5 - Identical to above...
// : break(25em) 8 - Breakpoint + column math (default)
// : 60em - Arbitrary width
// : static 60em - Use 'width' instead of max-width
// Example: 4 column default width, breaks at 8 columns
.container {
@include grid(4, break(8));
}
// ----------------------------------------------------------------------------
// Grid-Spanning Element
//
// @include grid-span($width, $position)
// - $column : [location | first, last <explicit>] [<width> | <columns-span> of <column-count> | <fraction>] [push <count> | pull <count>];
// : first - Remove 'outside before' gutters
// : last - Remove 'outside after' gutters (and reverse?)
// : 3rd - Explicit location
// : 2 - Columns in context (root)
// : 3 of 6 - Columns in context (explicit)
// : 2/6 - Fraction
// : push 3 - Push
// : pull 3 - Pull
// - $modifiers : [reverse] [in <context>] [gutter | <width>] [margin | <margin>];
// : reverse - Float the other direction
// : in 960px - Modify column context
// : in 75% - Modify column context
// : gutter 2% - Modify gutter
// : margin 10px - margins
// : margin 6px 10px - irregular margins
// Example: 4 of 10 Columns, pushed 3
.item {
@include grid-span(4 of 12 push 3);
}
// Example: Same as above using a fraction
.item {
@include grid-span(4/12 push 3);
}
// Example: Write a column of an arbitrary width.
.item {
@include grid-span(30%);
}
// Example: second 3 of non-uniform Columns pushed 1, new gutter .2
.item {
@include grid-span(2nd 3 of (2 1 5 1 3 3) push 1, gutter .2);
}
// Example: second 3 of non-uniform Columns pushed 1, new gutter 16px
.item {
@include grid-span(2nd 3 of (100px 60px auto 60px 140px 140px) push 1, in 960px gutter 16px);
}
// Example: Same as above, assuming global grid is OK.
.item {
@include grid-span(2nd 3 push 1);
}
// Example: span 5 columns assuming global grid, floats, and uniform columns
.item {
@include grid-span(5);
}
@mirisuzanne
Copy link

Interesting. I like the natural language direction we're headed - It can make things very easy to read and understand (if we do it well). Can you say a bit more about the changes you made, and why?

  • It looks like you removed the ability to set an arbitrary width for the layout item.
  • Can we distinguish between a column-in-root-context and a fraction?
  • How would "3rd push 1" be different from "4th"?
  • anything else?

@scottkellum
Copy link
Author

@ericam

  • It looks like you removed the ability to set an arbitrary width for the layout item.
    • yeah, I think I am most confused because I think of context as being divided by columns. Maybe we can just put an explicit sub-context in place of the columns to add that back in
  • Can we distinguish between a column-in-root-context and a fraction?
    • yeah, will add it in.
  • How would "3rd push 1" be different from "4th"?
    • When I think of push and pull I think of there not being a structural element to float off of. 3rd push 1 is the 3rd column floated next to an element that is the first column. Push just adds margins to compensate for the missing column.

anything else?

I am thinking of this in the way we built Singularity. That may be an issue, but let me describe the math behind it and why we calculate columns this way.

cascading defaults

Grid values seem to compound on defaults with Susy meaning that context is a function of the global context. So the of $columns variable scales gutters and other things based on the relationship to the global $columns.

With Singularity, the the defaults cascade instead of compound. IF you write of $columns I am thinking this overrides the global var instead of being a sub-context of it. $gutters remain unchanged and because the math is built on the relationships between the columns and gutters, not between the gutters and overall context, the gutters scale just fine when the grid is subdivided.

That said, I think the Singularity math can support the idea of traditional Susy context, but IMO we might want to switch to the Singularity math as it is incredibly simple.

the math

Easiest way to show this is by quick example.

Susy

100% / 12 = 12 column grid

This works great for any symmetrical grid logic. but lets nest that.

(100% / 12 * 3) : 100% = Three column context is a little more complex and percentages need to be compensated in gutters

2% gutters need to be expanded to fill appropriate new context.

Singularity

The basic language of Singularity only cares about ratios, not percentages, pixels, whatever. You can feed in (200foo 200foo 100foo) into a grid because units just don’t matter, it’s the relationship between them that counts.

1:1:1:1:1:1:1:1:1:1:1:1 = 12 column grid

gutters are translated a ratio of that, say .2

Now lets nest in a new context of 3

1:1:1 = exact same calculation as the full grid

So how does this work with gutters? again, the value cascades down and does not need to be recalculated in new contexts.

1 : .2 : 1 : .2 : 1 : .2 : 1 : .2 : 1 : .2 : 1 : .2 : 1 : .2 : 1 : .2 : 1 : .2 : 1 : .2 : 1 : .2 : 1

and when you nest, the length of the chain just gets smaller as we go down to 3.

1 : .2 : 1 : .2 : 1

It gets even better with asymmetric columns

12 : .2 : 38 : .2 : 12 : .2 : 23

Down to 2 columns

38 : .2 : 12

Would love to model the Susy 2.0 math on this. I think we can easily support anything on the fron-end with this, just involves a little different way of thinking.

partly why I overlooked the arbitrary context. I think we can work it out though. Maybe like this:

$context: ($new-context ($context - $new-context))

TL;DR

Calculating based on ratios between columns not outside-in context calculations might make some things easier and make some settings irrelevant. It might change the way settings cascade and how use cases work.

@mirisuzanne
Copy link

Cascading math: Oh, that is clever. I think you are right that your math should support either api. 4em : 1em is a ratio just the same as 1 : 0.25.

Arbitrary widths: I also think in terms of columns, but I am curious about this working as a gridless layout system. If I'm given a grid-free design comp to translate, I could still take advantage of the layout mechanisms, while supplying my own widths. Once a user is off-the-grid, though, I don't think we need to track how columns fit within that context.

3rd push 1: Aha. I was thinking "3rd" as in "isolated at column 3", in which case the isolation-placement and the pushing would both utilize the left margin, to accomplish basically the same task. But you are using "3rd" to establish which column-size to use in an asymmetric grid. In that case, we possibly use "push/pull 3" to move an item from it's floated location - or "at 3" to isolate it's location relative to a container.

@mirisuzanne
Copy link

oh, jut saw:

// Example: inside a specific context, not sure how exactly I feel about this, a little confused by it to be honest.
.item {
  @include grid-span(4 of 6, in 30%);
}

That would confuse me as well. I was thinking of this much simpler case - ignoring the grid entirely:

.item {
  @include grid-span(30%);
}

@scottkellum
Copy link
Author

Cascading math: Yup, and we can easily translate to this by dividing ($context - $gutter-total) / $columns = (100% - (2% * 3)) / 4 = 23.5 : 2 : 23.5 : 2 : 23.5 : 2 : 23.5.

a context of two: 23.5 : 2 : 23.5

love this stuff.

3rd push 1: yeah, gets a little complicated with asymmetric grids. At 3 might be better but i think the language here needs some work.

Arbitrary widths: AH! I get it now, thanks that makes much more sense now.

@scottkellum
Copy link
Author

some ideas for identifying the column location

grid-span(2 at 3 of 12)
grid-span(2@3/12)
grid-span(3rd 2 of 12)
grid-span(3 to 5 of 12) // not very compatible with non-located syntax.
grid-span(3-5/12) // not very compatible with non-located syntax.

@mirisuzanne
Copy link

Yeah, I'm liking this for the first argument:

// [ <selection> ] <width> [ <context> <location> ]
// - selection: first | <nth> | last » select specific asymmetric columns to use, and manage row edges if needed.
// - width: <width> | <columns> | <fraction> » (required) width as columns, arbitrary length, or fraction.
// - context: of <context> » nested context if needed.
// - location: at | push | pull | <count-or-width> » arbitrary width or column-count, for isolation or movement. 

@include span(2 of 12 at 3); // symmetrical: 2 columns, 12 column context, isolated in the 3rd position.
@include span(last 30%); // arbitrary: 30% width, treated like susy "omega" (if needed).
@include span(3rd 6 of 12 at 3); // asymmetrical 6 columns (3rd-9th), 12 column context, isolated in 3rd position.
@include span(1/5 push 25%); // fractional 1/5 width, pushed 25%

Notes:

  • That final example feels slightly redundant (3rd... at 3) but I don't know that we want to automatically conflate your selection of columns (3rd 6) with your desire to have the position isolated (at 3). You may want 3rd 6 of 12 to remain floated in the natural flow of things.
  • We should avoid overloading fractions with grid meaning, when they already hold meaning on their own.
  • Context and location can happen in any order: 3 of 6 at 2 == 3 at 2 of 6 and 2 of 12 push 4 == 2 push 4 of 12.
  • Selection is also easy to re-arrange, but makes most grammatical sense at the beginning.
  • We could add post | prefix | suffix to the location list pretty easily, to take care of any additional margin/padding.

Questions:

  • With asymmetric grids is a column-count sufficient context? If you have a 12-column asymmetric grid, and you give a context of 8, don't we need to know which 8? 3rd 3 of 2nd 8? That seems difficult.

Modifiers:

  • Why do we have column context here (in 960px) as well as in the first argument (of...)?
  • What all else do we need to manage here? How does each thing work?

Things we might want to modify:

  • gutter size & location (inside/outside and before/after/split).
  • padding & margin, if they aren't already covered by the above.
  • float direction
  • box-sizing?
  • others?

@scottkellum
Copy link
Author

This is starting to look really awesome, I think we should drop 3rd and just use at 3 Keep things simple and consistent.

Yeah, really like the idea of moving these around: 2 of 12 push 4 == 2 push 4 of 12

With asymmetric grids is a column-count sufficient context? — No, the idea here is that 12 completely re-writes the gird each time. This just resets the grid to a regular 12 column grid. If the context is $grid: (1 2 4 4 2 1); and the nested mixin for the second two columns would be like this grid-span(1 of (2 4)). If it was just grid-span(1 of 2) then it would result in two equal columns. Also this is super flexible and plays nice with the math.

Why do we have column context here — Sometimes columns are nested or just written as something off the normal grid. If you want to configure a special context that is different from the default grid, this is where you can pass one in. Maybe you are nesting deeper than 3 layers in markup as well and need to define an explicit sub-context.

••What all else do we need to manage here•• — These modifiers just change global settings. We should have an override for ever global variable here. I think we can safely delay going too deep into these until we get our width/location and global vars working smoothly. Your list is a great start, lets run with that for now. Maybe change output settings (float, isolation, table) but we still need to get language parsers, math and partial structure going before we look into output API.

@mirisuzanne
Copy link

This is all looking great for simple grids, but I have concerns about the asymmetric approach. Maybe I just don't understand it fully?

  • I think the choice between float and isolation should be handled in a fine-grained way, rather than project-wide. That's because I think isolation is a great solution to a rare problem, and a terrible solution the rest of the time. I see at 3 as a simple way to trigger isolation, without any need for global settings or other modifiers. That's why I like 3rd and at 3 to serve different purposes. One is used to determine column width in asymmetric grids, and the other to trigger isolation placement. If you combine them, does that mean asymmetric grids will always use the isolation method?
  • It seems like asymmetric nesting context could get very verbose and difficult to manage. Will we need a good way to automate it, so I don't have to remember my column ratios every time I span a nested context?
  • Couldn't special contexts be handled in exactly the same way as normal grid-column contexts? span(2 of 960px)?

I like your idea of working our way out from this. Should we start by building this single mixin, with only the width/location argument?

@scottkellum
Copy link
Author

  • To be a little more clear, I consider at 3 to be location, not isolation. Float and isolation are output types, not relating to this syntax. Location is needed to calculate the grid width in asymmetric columns so we should be focusing on that alone for this area of syntax. Location is irrelevant for uniform columns and the syntax should . I think we need to make the output distinction in the modifiers but that can wait until we have all the math working properly. We can use floats for everything, including asymmetric columns, for now. We can also add smart triggers to switch to isolation or another output mode if the column is written in such a way that implies the user wants to use it.
  • It seems like asymmetric nesting context — I will play, see if we can simplify at all. Maybe @Snugug has ideas. My biggest fear is that automation will make things more opaque.
  • Couldn't special contexts be handled in exactly the same way as normal grid-column contexts? — Are you saying that the global context is something like 100% and span(2 of 30%); is the special context? A little confused by sub-dividing special contexts. I was designatinginas the grid context andofas the division of that grid context when thinking about this. Soof 12 in 960px, gutter 20pxwhere we have a context, how it is divided, and we can calculate 20px gutters appropriately for this given context. Doesspan(2 of 960px)` change only the grid context and is this still a 12 column grid? or is this 2 of what in the context of 960 in some larger number?
  • Should we start by building this single mixin — I think we need to have an outline for code style and architecture first so everyone can get on the same page then we can start building the various components necessary. We might need a math partial to handle calculations and such and a string parser to handle the language in the mixin.

@tsi
Copy link

tsi commented Dec 24, 2012

guys, I've been really sick the last few days so reading this for the first time just now. honestly, it's a bit hard to grasp I think mainly because I don't fully understand the implications of adding the ability to have asymmetric grids.

I like what you've reached here. I love that you can both do:
@include span(30%);
and:
@include span(2nd 3 of (100px 60px auto 60px 140px 140px) push 1, in 960px gutter 16px);
In that you can do complicated stuff, but that doesn't mean we complicate simple tasks. I really dislike forcing the developer into doing complicated grid calculations when all he wanted was something simple like placing an image next to a text block.

I agree with Eric about the 3rd and at signification. I, too, understand at as being an alternative to push or pull that uses the isolation (container-relative floats) method for that specific item. That means I can do:

@include span(2);        // simple, in-the-flow float.
@include span(2, at 8); // container-relative float, positioned at the 8th column.

I'm not 100% happy with using 1st, 2nd, 3rd etc. because of the inconsistency (st/nd/rd) and the need to understand the quirks of the english language. I'd prefer a single keyword instead. but if that is the best solution we have than I guess it will do.

@scottkellum
Copy link
Author

@tsi and @ericam

In my mind, at and push/pull are two completely different things.

at — designates the location a column starts. Helps identify how wide an asymmetric column should be. If using the isolation method/grid layout/an output that supports location, the column can be written at that location.
push/pull — Useful with float output that does not support location. If there is not a structural column preceding the current column, this adds margin to put the column in the correct location.

Because we don’t know anything about the HTML, I don’t see how we can get at and push/pull to work the same way. We would need to know the markup in order to correctly float span(1 at 1) next to span(1 at 3). While this would work in isolation methods, symmetric floats would need to be written span(1) and span(1 push 1). Asymmetric columns with floats like this: span(1 at 1) next to span(1 at 3 push 1).

Not sure why we need both 3rd and at. I think triggering output modes should also be more explicit as we might want to support grid layout and other output modes other than just float and isolation in the future.

cc/ @Snugug as he has been in the thick of this stuff as well.

@tsi, lots of this thread has been refining what @ericam wrote and sanding off edge-cases. I think we can safely remove comas in favor of identifying variables with consistent prefixes like at, of, push and pull.

@mirisuzanne
Copy link

What @tsi and I are arguing is not that isolation and push/pull are the same thing or work in the same way, but that they are alternatives for managing the same concept: location. push/pull change location relative to the flow (pushing or pulling the item to a new location), while isolation is relative to the container (setting it at a specific location), but they accomplish the same conceptual task. They are comparable to relative and absolute positioning in that way. We don't need to know anything about your markup to let you use whichever approach you prefer in each case. See my note in Do.

span(2 at 3) != span(2 push 3)
span(2 at 3) // should trigger isolation in the 3rd column.
span(2 push 3) // pushes 3 columns off the current flow.

We also understand that a distinct argument is needed for handling asymmetric column selection, separate from the argument used for isolation. Again, I make a proposal for that in Do.

I could also see using "isolate 3" in place of "at 3" for isolation, which would mean "at" is still available for asymmetric selection, but I find it unclear as a syntax for that.

@scottkellum
Copy link
Author

span(2 at 3) Can this trigger isolation only if it is used with a uniform grid? There might be instances where float method is preferred and the at 3 is still necessary to find width?

IDK, maybe I am over complicating things. Just seems like there might be use cases were this automatic behavior might not be wanted?

Maybe isolate at 3 or float at 3. We can have this magic but override it in explicit instances. IMO at should not be limited to an output mode, while it can trigger an output mode it worries me a little strictly tying it to an output mode. Just trying to think of a good way to float asymmetric columns instead of isolating them.

@mirisuzanne
Copy link

One of us is misunderstanding, because I don't think there is any automatic or magic in my proposal. I'm not suggesting that at would automatically isolate asymmetric grids. I'm suggesting that at would have nothing at all to do with asymmetric grids. I'm suggesting that it would do isolation instead of, not in addition too asymmetric grids. So at would only do one thing, and it would do that one thing explicitly, without any magic.

And then, since we need a way to do asymmetric grids as well, I'm suggesting entirely separate solutions for that. My favorite approach for that is to declare a range of columns (e.g. 2 to 4 of (2 4 6 8 6 2) would span the 4 6 8 columns) rather than a column count and a starting point - which is what you are proposing with at.

Does that make more sense? If it still sounds automatic, I haven't explained it well. :)

@scottkellum
Copy link
Author

2 to 4 of (2 4 6 8 6 2) — this language feels more like isolation.

I am most worried now that we have far too many different styles of defining location on the table now with 2nd, at, and to. Semantically I don’t see the difference between 2nd and at 2 and still think we should choose between one of the two, I am leaning towards at. If you see differences between these two I think they need to be VERY carefully documented.

I think I know what the confusion is. It seems like you are thinking of non-uniform grids as using a different syntax from non-uniform grids while I am trying to find a unified syntax. I am pretty worried about having two different syntaxes for both types. Would love to just add a location to support non-uniform instead of having a completely different 2 to 4 style syntax.

@mirisuzanne
Copy link

Sorry, maybe I don't understand all the categories. What is a uniform asymmetric grid, as opposed to a non-uniform one?

@scottkellum
Copy link
Author

Sorry, not keeping my language consistent. “uniform” = “symetric” and “non-uniform” = “asymmetric”. Uniform and non-uniform are a little more specific. That language was pretty bad and confusing, fixed now.

@Snugug
Copy link

Snugug commented Dec 26, 2012

Let me weigh in on some of this:

Isolation vs Float
I really dislike the idea of automatically assuming isolation/float based on how syntax. Output style needs to be explicit because there are significant and potentially unexpected issues with using one over the other, so what output style that gets used needs to be a user choice not a system assumption. Both Float and Isolation work perfectly well for uniform/symmetric and non-uniform/asymmetric grids, and by explicitly requiring users to define their output style it opens us up to other output styles and a plugin output architecture. It also keeps up future friendly.

Where Are You
I'm a big fan of the natural language stuff we've got going on here, but let's take a step down and think about the code. As we all know, Sass's built in functions for string parsing aren't so great, so we're going to need to set our syntax to something that's easily parseable with this in mind. As such, I'm in favor of the at/to syntax as opposed to an ordinal number system. It's going to make it much easier come code time for us to parse. It's also easier to grok if you're not a native English speaker as ordinals are fracking strange.

At/Push/Pull
Here's where stuff, in my mind, starts to get tricky. At can, as a concept, take on entirely different meanings depending on whether your output is symmetric, asymmetric, float, or isolation. Let's break it down:

  • Symmetric Float: With a symmetric float output where which column on the gird is irrelevant, at very easily can mean push/pull (although span(3 at -1) seems a bit odd to me). span(3 at 2) sounds like it could be a push.
  • Asymmetric Float: Here it gets complicated. We need a way to specify both which column on the grid to use and a way to push/pull. Because we are using float output and not isolation output, we don't have the positioned margins to rely upon, so we need a way to do both separately. In this instance, at more easily portrays column on grid and push/pull more easily portrays positioning.
  • Symmetric Isolation: Symmetric grids with isolation output are interesting to deal with. On one hand, you don't need need which column on grid in order to effectively size an element. On the other, you do need it for positioning due to how the system works. With that said, I believe that this could work similarly to symmetric float.
  • Asymmetric Isolation: The kicker (for the time being). Because you again need to be able to determine both position and column on grid, we're left in the same position as asymmetric float of needing to have two different syntaxes to effectively do this (why you would push/pull an asymmetric grid's columns on itself is a different question though).

Hopefully that's clear and shows a clear need for both at and push/pull in the system, Because we have a strong need for both, we could either say that symmetric grids have one syntax and asymmetric grids have another, or I believe that for symmetric grids, while at can work, push/pull can work equally well and we can have a unified syntax across both types of grids, making the DX better in the end and making switching between output methods nice and easy.

With all of this being said, I think that while we can have push/pull functionality built in to +span(), we need to also have +push() and +pull(). Something I frequently do is lay out a base grid for major page components using one grid and have items inside that grid laid out on another. True compound gridding. In this case, I have the need to push/pull not only along the grid I'm currently on, but along a different grid altogether. As such, we need a distinct way to enable this, and I think trying to cram it all into a single line is a bit much. Separate mixins are required.

Global Variables
While I agree and fully support the need to be able build an entire grid from +span(), I do still believe that we need some global variables. Specifically, the following (with inline overrides as needed):

  • $grids: A way for users to define major grid changes at given breakpoints.
  • $output: The default output method. Could be overridden with using float.
  • '$gutters`: The default gutter options, mostly for convenience.
  • $border-box: Boolean. Include box-sizing: border-box on all grid items or not. Could be overridden with with border-box or without border-box.
  • $clearfix: Boolean. Include a clearfix on all grid items or not. Could be overridden with with clearfix or without clearfix.

Defining The Grid, Breakpoints, and Containers
Back to the string parsing issue I brought up in float/isolation, IMO we're going to need a slightly more verbose syntax for defining an individual grid than currently proposed simply due to parsing issues and uneven numbers of variables (unless one of us is a natural language parsing savant that I'm not aware of). I'm not sure what that's going to need to be ATM, but I think it's going to be needed.

As for defining breakpoints and containers, I actually really hate column based breakpoints. I understand people use them, but they are always desktop-first approaches and rarely if ever actually line up with what your content needs. While having it as an option for those who want it, it needs to be much more explicit in what it's looking for including a min or max column width. This is especially true when talking the compound math that we're using in Singularity and what we should be using in Susy Next (screw 2.0, Susy Next!) as everything boils down to, and can be explicitly set as, unitless numbers. We also need to take into consideration, especially if we're writing container widths in ems, changing base font sizes (aka font scaling) at different breakpoints and taking that math into account. We also need to be able to explicitly provide a progressive enhancement fallback. I also think it should be called +container() not +grid() as we're not adding a grid, but rather adding a container.

Overall Thoughts
Generally speaking, I think we must follow the below principles when architecting Susy Next in order to accomplish not only what we individually want, but for our users and for future friendliness:

  • Things Cannot Be Made Harder If something is currently easy to do, say defining responsive grid sets, it cannot be made harder or omitted in the new system. It may be different, but it cannot be harder, at least not significantly so.
  • Plan For The Future A fluid grid is fundamentally easy: give me X pieces that are in Y proportion to the whole. We should only make assumptions based on that. Anything else, from moving around the grid to how it should be output to whether to include things like border-box or clearfix should be up to the user to decide. We should not, for instance, assume that the type of grid they want to use should dictate the output. Any of these assumptions will make it harder for us to keep future friendly and generally be flexible.
  • Encourage Good Habits While we cannot force users to use ems for container widths or build mobile first, the code and documentation we write should all reflect good habits and best practices and we should actively discourage bad practices. This includes encouraging off the bat responsive web design, being future friendly, mobile first development, and fluid grids. We can provide the tools to build using good habits based on a user's current knowledge level, say being able to convert 300px 600px 250px 300px into a 3 6 2.5 3 grid, but users should never be under the assumption that their bad habits are going to be rewarded. An instance of this (please do not take offense Eric) is assuming a grid of 12 4em 1em will create a 60em container. This is a bad habit because this is a desktop first approach to building a grid; the way we break people of this bad habit is by requiring containers to be set explicitly, separating the relational grid math from the design container code.

I think that's enough for this morning. For everyone who celebrated, hope everyone had a great Christmas!

@scottkellum
Copy link
Author

Just popping in to say I wrote a quick function that can make some natural language parsing work pretty well: https://github.com/ericam/susy/blob/susy2_math-engine/sass/susy/_math.scss#L24

Still issues with identifying the unperfected span number in code. Would love to think about this stuff without worrying about how it can be parsed, I’m sure we can make something work and user-facing stuff seems most important. But Susy is an interface for math and there is a lot of code we should be thinking about now.

+1 @Snugug on other points.

@mirisuzanne
Copy link

Agreed on all counts, with some questions still remaining :). Great write-up @Snugug. @scottkellum, I'll have to play with that function to understand it better, but it looks sweet. Thanks!

I agree that we should always allow as much as possible, while pushing best-practice defaults. The current defaults are a legacy problem, not a decision to push desktop-first approach. I'm also certain we will need at least most of the global settings mentioned, and possibly a few more. Mainly I'm interested in determining each feature we need to handle, and then the best way to handle it at each level (local & global) as needed. I think we're on track for that.

I don't think anyone has proposed that float/isolate should be automatic. We all agree that output should be explicit in every way. It's just a matter of nailing down how each feature is stated.

As I understand, here are the arguments that we need (and some proposals for how they might work):

  • Arbitrary width: 30% or 30em or 300px (easy!)
  • Uniform column span, with optional context: 3 or 3 of 6
  • Non-uniform column span, with location-select and optional context: 3 at 3 or 3 at 4 of 12
  • Pushing & pulling: push 4 or pull 3
  • Isolated location: isolate 4

More on isolation:

Isolation is not an entirely distinct grid output type, it's simply a way of moving your columns around. It is the "absolute" alternative to the more "relative" push/pull. It's a local decision, not a global one. Here's two reasons:

  1. Since isolation requires an extra argument on each element anyway, I don't see any reason for a global setting. If the argument is passed, you want isolation, if it isn't, you want floats. That's not automatic, it's explicitly called with it's own syntax:
$output: isolate;

// this is required either way (with or without the global setting), and works fine without it.
// the global setting has accomplished absolutely nothing.
.thing { @include span(3 isolate 4); } 
  1. It's bad for the flow, requires extra markup & css, and is basically a hack. We should not be pushing this as a global setting - we should be pushing it as an option you use in the few cases where it really can help.

More on non-uniform location-selection (which column widths to use):

I'm not entirely convinced that <span> at <location> is the best syntax for working with non-uniform grids. I was never suggesting that we use at for both location and isolation - only that I think it works better as an isolation syntax than it does as a location syntax. To me, it seems strange to define non-uniform spans based on their count and starting-point. We don't actually care how many are spanned (and neither does the user) - what matters is where we start and where we end. Why not base the syntax on start and finish, rather than start and count? We could use <start> to <end>?

// Say we want to span columns 4-7 (3 columns) of a non-uniform 12-column grid

// your proposed syntax takes start (4) and count (3):
.thing { @include span(3 at 4); }

// my syntax doesn't care how many - only where we start (4) and where we end (7):
.thing { @include span(4 to 7); }

@Snugug
Copy link

Snugug commented Jan 2, 2013

I think we should decouple the idea of isolation and float. The reason I suggest that they are global settings is because:

  1. We are not just dealing with float vs isolation, we want this system to eventually be able to do CSS grids, tables, etc…
  2. Some people (like John and many Gridset users) will want to use Isolation for all of their items. It's a grid output style like any grid output style. I think we should keep it simply like that.

@Snugug
Copy link

Snugug commented Jan 2, 2013

I think we should decouple the idea of isolation and float. The reason I suggest that they are global settings is because:

  1. We are not just dealing with float vs isolation, we want this system to eventually be able to do CSS grids, tables, etc…
  2. Some people (like John and many Gridset users) will want to use Isolation for all of their items. It's a grid output style like any grid output style. I think we should keep it simply like that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment