I have implemented a fluid layout with Semantic.gs and some nested columns with LESS. But now our client decided they want the layout to be fixed.
I thought I could simply comment out the line #total-width:100% in grid.less, however now the other LESS files give an error on lines with the .row() mixin.
Is there a workaround for this?
Here is the relevant portion of grid.less
/////////////////
// Semantic.gs // for LESS: http://lesscss.org/
/////////////////
// Defaults which you can freely override
#column-width: 20;
#gutter-width: 10;
#columns: 47;
// Utility variable - you should never need to modify this
#gridsystem-width: (#column-width*#columns) + (#gutter-width*#columns) * 1px;
// Set #total-width to 100% for a fluid layout
//#total-width: #gridsystem-width;
//#total-width: 100%;
// Uncomment these two lines and the star-hack width/margin lines below to enable sub-pixel fix for IE6 & 7. See http://tylertate.com/blog/2012/01/05/subpixel-rounding.html
#min-width: 980;
#correction: 1 / #min-width * 100 * 1.5%;
Here is the problematic section of the LESS file. The LESS compiler gives the error 'Compiler Errors
variable #total-width is undefined (Line: 292)', which is the line with the .row() attribute:
#v_main_wrapper{
position:relative;
float:none;
.row(47);
&:after{
content: "";
display: table;
clear: both;
}
}
I would think that you would want this:
#total-width: #gridsystem-width; //leave this uncommented, to calculate width
//#total-width: 100%;
Related
I'm looking to see if anyone has ever had any experience with this CSS syntax debate we are currently having on our team. Our dev team has been using the vim plugin Tabular to align text in our code. For example in PHP or Javascript we will align variable declarations using the plugin like this:
$count = 0;
$var_1 = array();
$var_2_long_name = array();
$stdout = fopen( 'php://stdout', 'w' );
$some_data = json_decode( $some_json_data, true );
Helps the code look clean and easy to read.
We have considered using alignment in our CSS (we are using LESS but this question could be applied to SASS or just straight CSS). For example we would change this block:
.btn-section {
position: relative;
top: -65px;
display: block;
z-index: 100;
.content-box;
background-color: #grayButton;
color: #gray;
padding: 10px 0;
.border-radius(5px);
}
To this:
.btn-section {
position : relative;
top : -65px;
display : block;
z-index : 100;
background-color : #grayButton;
color : #gray;
padding : 10px 0;
.content-box;
.border-radius(5px);
}
One of the devs experimenting with this tactic moved the mixins from their original spots to the bottom of the declaration in order to make the code "look right" since mixins don't conform the the normal selector: value; format of regular css. In this case, the .content-box mixin had a background-color declaration that was being overridden by the backgroud-color line beneath it. Moving the mixin to the bottom broke the override and gave the element the wrong background color.
Errors like this coupled with the extra steps it takes to format every single block of CSS make me think this might not be such a good idea. Has anyone ever tried this type of alignment before? Any opinions on whether this is a good or bad idea? Thanks.
I think your alignment tactic is a good idea, I'd just recommend turning it upside down:
.btn-section {
.content-box;
.border-radius(5px);
position : relative;
top : -65px;
display : block;
z-index : 100;
background-color : #grayButton;
color : #gray;
padding : 10px 0;
}
That way the more general mixin styles would be applied first, after which they may be overridden by selection specific adjustments instead of the other way around.
By doing it like this, you eliminate this risk of accidently overriding specific styles with inherited ones and still keep everything neat and easy to read.
I am using singularity.gs (Drupal 7/Omega 4), and I want to stack my content in columns.
In 960gs, you just add grid-4 to the element, and it spans 4 columns with appropriate margins (more or less).
To make a 12-column grid with sigularity.gs I've written this:
.grid-4 {
width: column-span(4, 6);
margin-left: gutter-span();
float: left;
}
.grid-4:first-child {
margin-left: 0;
}
Is there a simpler or more idiomatic way to do it?
I'm not sure if this is a question per se, but I think I can answer it.
Singularity allows different output styles to provide their own span mixins to better adhere to that output style's mental model. 960gs works on the float output style, allowing you to to change what you have to the following:
.grid-4 {
#include float-span(4);
&:nth-of-type(3n) {
#include float-span(4, 'last');
}
}
A working SassMeister with this should give you a clear idea of what's going on.
Question
Is there any way to (programmatically) throw an error in the LESS compiler?
Why?
I have been fiddling around with mixin guards today, because I wanted to generate my CSS margin based upon element size and element count.
I thought it would be cool to directly throw an error on compilation, when the elements won't fit in the wrapper.
Info: I am using the lessc compiler to compile my LESS code to CSS. I am not using any Javascript library to compile it on execution time.
LESS source
// Variables
#wrapper-small: 830px;
#wrapper-big: 1200px;
.col-fixed(#size, #count, #wrapper) when ((#size*#count) <= #wrapper)
{
width: unit(#size, px);
margin-right: unit( (#wrapper - #count * #size) / (#count - 1), px);
}
.test_col_fixed {
// will fail the mixin guard and output no generated CSS
.col-fixed(340, 3, #wrapper-small);
// would work if not in comment
// .col-fixed(340, 3, #wrapper-big);
}
Generated CSS (small wrapper)
No output, because the code will not be generated due to the not matching mixin guard when ((#size*#count) <= #wrapper) // 3*340 <= 830 is false.
Generated CSS (with working solution, big wrapper)
.test_col_fixed {
width: 340px;
margin-right: 90px;
}
Suggested, but strictly not recommended solution by Harry
.col-fixed(#size, #count, #wrapper) {
& when ((#size*#count) <= #wrapper) {
width: unit(#size, px);
margin-right: unit( (#wrapper - #count * #size) / (#count - 1), px);
}
& when ((#size*#count) > #wrapper) {
/* there is no such variable and hence when the input value is not valid,
compiler will complain that variable is undefined */
output: #bwahahaha;
}
}
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!
I'm looking for a way to do something like this:
// style.css
#def borderSize '2px';
.style {
width: borderSize + 2;
height: borderSize + 2;
}
where the width and height attributes would end up having values of 4px.
Sometimes I use the following:
#eval BORDER_SIZE_PLUS_2 2+2+"px"; /* GWT evaluates this at compile time! */
Oddly, this only works, if you don't put any spaces between the + operator and the operands. Also, in #eval you can't use constants that were previously defined by #def. You can however use constants that are defined as static fields in one of your Java classes:
#eval BORDER_SIZE_PLUS_2 com.example.MyCssConstants.BORDER_SIZE+2+"px";
Or you could let the calculation be performed completely by Java:
#eval WIDTH com.example.MyCssCalculations.width(); /* static function,
no parameters! */
#eval HEIGHT com.example.MyCssCalculations.height();
.style {
width: WIDTH;
height: HEIGHT;
}
But what I would actually like to do is very similar to your suggestion:
#def BORDER_SIZE 2;
.style {
width: value(BORDER_SIZE + 2, 'px'); /* not possible */
height: value(BORDER_SIZE + 3, 'px');
}
I don't think that's possible in GWT 2.0. Maybe you find a better solution - here's the Dev Guide page on this topic.
Mozilla kind-of-sort-of-not-really supports this with it's CSS calc() function.
This example shamelessly stolen (with attribution!) from Ajaxian
/*
* Two divs aligned, split up by a 1em margin
*/
#a {
width:75%;
margin-right: 1em;
}
#b {
width: -moz-calc(25% - 1em);
}
It's not cross-browser, and it's probably only barely supported by even bleeding-edge versions of Firefox, but there's at least being progress made in that direction.
You could also calculate in your provider method, if you put a parameter in the function:
#eval baseFontSize com.myexample.CssSettingsProvider.getBaseFontSize(0)+"pt";
#eval baseFontSize_plus_1 com.myexample.CssSettingsProvider.getBaseFontSize(1)+"pt";
com.myexample.CssSettingsProvider would look like this:
public static int getBaseFontSize(int sizeToAdd) {
if (true) {
return 9 + sizeToAdd;
}
return baseFontSize;
}
I would also love somehting like that, but it's not possible.
Even in CSS 3 their is nothing planned like this.
If you really want to make something like that, one possibility is to use
php and configure your webserver, so that .css files are parsed by php.
So you could do something like
<?
$borderSize = 2;
?>
.style {
width: <? borderSize+2 ?>px;
height: <? borderSize+2 ?>px;
}
But as this is no 'standard' way, i think its better to not do it.