Trying to figure out Susy and am having trouble positioning elements by location. ‘first’ and ‘last’ work as expected, but using the number of a specific column doesn't. Where am I going wrong?
.number {
#include span(4 at 5);
}
see demo: http://sassmeister.com/gist/aad8a46d927b59573695
or full code:
#import "susy";
$susy: (
flow: ltr, // ltr | rtl
output: float, // float | isolate
math: fluid, // fluid | static (requires column-width)
column-width: false, // false | value
container: 800px, // length or % | auto
container-position: center, // left | center | right | <length> [*2] (grid padding)
last-flow: to,
columns: 12,
gutters: .75,
gutter-position: after, // before | after | split | inside | inside-static (requires column-width)
global-box-sizing: content-box, // content-box | border-box (affects inside/inside-static)
debug: (
image: show,
color: rgba(#66f, .25),
output: background, // background | overlay
toggle: top right,
),
use-custom: (
background-image: true, // look for background-image mixin
background-options: false, // look for background-size, -origin and -clip and other compass/bourbon mixins
box-sizing: true, // look for custom bix sizing mixin
clearfix: false, // true = look for internal clearfix before using micro clearfix
rem: true, // look for rem mixin
)
);
.page {
#include container;
}
.row {
#include full;
}
.first {
#include span(4);
background-color:pink;
}
.last {
#include span(last 4);
background-color:orange;
}
.number {
#include span(4 at 5);
background-color: wheat;
}
<div class="page">
<div class="row">
<div class="first">hooray I'm first</div>
<div class="last">hooray I'm last</div>
</div>
<div class="row">
<div class="number">boo I'm not at my specific location</div>
</div>
</div>
Just realized my error (in case anyone else needs it): the 'at' keyword only works with isolate output and my grid is set to float. To fix you can change float to isolate in the overall settings, or apply it directly to the element in question.
.number {
#include span(isolate 4 at 5);
}
http://sassmeister.com/gist/42d1efaf1ddd9c721379
Related
I have some JS functionality that changes the css class on my body element. Based on a click, i will change the css class of my body element to one of the following: .font-default, .font-medium, and .font-large.
I have the following mixins that determines the font size of an element based on the body element's class. That looks like this:
#function rem-calc($size) {
$remSize: $size / 16;
#return #{$remSize}rem;
}
#mixin font-size($size) {
#if $size >= 20 {
font-size: rem-calc($size);
} #else if $size == 18 {
font-size: rem-calc(18);
.font-large & {
font-size: rem-calc(20);
}
} #else {
font-size: rem-calc($size);
.font-medium & {
font-size: rem-calc($size + 2);
}
.font-large & {
font-size: rem-calc($size + 4);
}
}
}
An example of me using this mixin is as follows:
.content {
#include font-size(16);
#media (min-width: 1024px) {
#include font-size(30);
}
}
Here's is the corresponding html and css on the linked codepen at the bottom:
<body class="body">
<div class="content">Content</div>
<button class="button">
click to add
</button>
</body>
<script>
const button = document.querySelector('.button')
button.addEventListener('click', () => {
console.log(document.querySelector('.body'))
document.querySelector('.body').classList.add('font-medium');
})
</script>
According to my ruleset (the mixin), in the desktop version, font-size should remain unchanged since size >= 20. However in practice, when I click the button that changes the class to medium, it uses the "mobile" version of the style and overwrites the style that's placed in the media query.
Is there anyway regarding specificity such that I can still use this mixin so that the mobile styles don't bleed into the styles nested in the media queries?
If not, what might be a different solution to this problem?
Here's a pen that shows the issue. When clicking the button, I want the font to remain unchanged. https://codepen.io/rv-akim/pen/WVJpWj
You can clearly see that .font-medium .content is overriding .content due to the fact the former is more specific even though .content is inside of a media query.
Update your code so your normal state of the font size uses a class
#mixin font-size($size) {
#if $size >= 20 {
.normal & {
font-size: rem-calc($size);
}
} #else if $size == 18 {
.normal & {
font-size: rem-calc(18);
}
.font-large & {
font-size: rem-calc(20);
}
} #else {
.normal & {
font-size: rem-calc($size);
}
.font-medium & {
font-size: rem-calc($size + 2);
}
.font-large & {
font-size: rem-calc($size + 4);
}
}
}
.content {
#include font-size(16);
#media (min-width: 1024px) {
#include font-size(30);
}
}
Add class normal to your body tag
<body class="body normal">
Basically, where you only declared the font size rule, I wrapped it with .normal & {}
If you learn to use the Inspector, it will save you tons of headaches later
So the title is quite a mouth full, and I am struggling to get a exact answer for this on SO. I have a few child div's in a container div, that gets loaded with data form a database every time the page loads. Depending on the option chosen, the vertical size of the child div's change depending one the amount of information (No fixed size). But (due to the look and feel), I must have the child div's also overlapping and on-top of each other (using z-index), which means that the child div's all have the property of position:absolute. This means that as they expand, they just expand past the bottom edge of the parent container without "pushing" it along, or making it larger.
So I would like to know that the best way would be in Angular2 to get the size of the child div's, use the largest size, and set the parent height to this size (+ lets say 20px). Because it is Angular2 I don't just want to use jquery seeing as that is not the way to use Angular.
So I added my code to show what I have at the moment:
import { Component, OnInit } from '#angular/core';
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'nlr-container-bottom-footer',
template: `<div id="main">
<div id="boks3">
* <br>
* <br>
* <br>
* <br>
* <br>
* <br>
* <br>
* <br>
* <br>
* <br>
* <br>
</div>
<div id="boks2">
* <br>
* <br>
* <br>
* <br>
</div>
<div id="boks4">
* <br>
* <br>
* <br>
* <br>
</div>
</div>`,
styles: [`
#main {
background-color: yellow;
}
#boks2,
#boks3,
#boks4
{
background-color: red;
width: 32%;
position: absolute;
margin-left: 33.5%;
padding: 0px 0px 0px 5px;
z-index: 3;
text-align: left;
}
#boks2 {
background-color: blue;
margin-left: 17%;
z-index: 2;
height: 100px;
}
#boks4 {
background-color: green;
margin-left: 50%;
z-index: 2;
text-align: right;
height: 100px;
}
`],
})
export class ContainerBottomFooterComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
So as you can see it gives three boxes, two at the "bottom" and one on top of them. The fact that they have to be stacked, is also why they have to be "position:absolute". But as you can see the text in all three boxes just go past the height of the main container (or does not even effect it at all).
So I am trying to find a way to get the height of the largest boks, and then pass that height on to the main container.
Any help would be much appreciated.
Regards
-- UPDATE # 2 --
export class ContainerBottomFooterComponent {
#ViewChildren('.plates', {read: ElementRef}) //Here we say "Go look at the children (there is more than one) classes called 'plates', it then looks like we are reading all the ElementReferences of those classes"
public books: QueryList<ElementRef> //Here we are giving the variable "books" the list of off all the references of all the classes.
#ViewChild('main', {read: ElementRef})// Here we are reading a single reference of the div with id "main"
public mainContainerRef: ElementRef; // Here we are giving the variable mainContainerRef the element references of the div with ID class #main
constructor( private _renderer:Renderer) {
let height = this.books.reduce((height, bookRef) => {
let rect = bookRef.nativeElement.getBoundingClientRect();
return rect.height > height ? rect.height: height;
}, 0);
}
ngAfterViewInit() {
this._renderer.setElementStyle(this.mainContainerRef.nativeElement, 'height', height + 'px');
}
}
You could use the ViewChildren Decorator:
#ViewChildren('.itsABook', {read: ElementRef})
public books: QueryList<ElementRef>;
#ViewChild('main', {read: ElementRef})
public mainContainerRef: ElementRef;
and then iterate over the QueryList:
let height = this.books.reduce((height, bookRef) => {
let rect = bookRef.nativeElement.getBoundingClientRect();
return rect.height > height ? rect.height: height;
}, 0);
and set the height of the main container using the Renderer:
this.renderer.setElementStyle(this.mainContainerRef.nativeElement, 'height', height + 'px');
HTML:
<div id="main" #main>
<div class="itsABook"></div>
<div class="itsABook"></div>
<div class="itsABook"></div>
</div>
Also keep in mind that the references for books and mainContainerRef are only available after ngAfterViewInit hook
Edit: Added reference for mainContainer
I was using the (transitionend)="onSizeChanged()" callback in my .html file and defined a transition like so transition: width 1ms, height 1ms; in my .scss which worked for me. In the adjustSize() method you can then set your desired width and height (presumably the dimensions of your absolute-positioned ViewChild) and bind the values in your parent div like so: [style.width.px]="width" [style.height.px]="height". When facing performance issues you can use a BehaviorSubject and subscribe to it, using auditTime() to debounce it.
HTML:
<div class="parent" [style.width.px]="width" [style.height.px]="height">
<div #child class="child" (transitionend)="onSizeChanged()>
/*this component can change in size*/
</div>
</div>
CSS:
.parent {
position: relative;
}
.child {
transition: width 1ms, height 1ms;
position: absolute;
}
Typescript:
#ViewChild('child') private child: ElementRef;
private _width = 0;
private _height = 0;
public get width(): number {
return this._width;
}
public get height(): number {
return this._height;
}
public onSizeChanged() {
this._width = this.child.nativeElement.scrollWidth;
this._height = this.child.nativeElement.scrollHeight;
}
I know this is sort of a hack, but it's not stupid if it works.
I'm building spritesheet buttons, something like this:
<a class="Button one"></a>
<a class="Button two"></a>
With style:
a {
// Add basic background and styling
background: transparent url("images/background_image.png") no-repeat;
// Add icon on top
&:before {
content: '';
display: block;
//....
background: transparent url("images/icons.png") no-repeat;
// (1)
&.one { #include tile(165px, 0, 0) }
&.two { #include tile(165px, 1, 0) }
}
// (2)
&.one:before { #include tile(165px, 0, 0) }
&.two:before { #include tile(165px, 1, 0) }
}
Now I want to add the variant styles, but (1) does not work, only (2). Is there no way to avoid repeating the :before?
If you take a look at the compiled CSS, you'd get something like this:
a:before.one { /* ... */ }
CSS pseudo-elements like :before and :after cannot have classes. If you want to make it shorter, one option would be to combine the classes:
a {
&.one, &.two {
&:before { #include tile(165px, 0, 0) }
}
}
But since you want to use different values for the mixin, I think #2 is the cleanest way to go.
I have this, but I feel 4 is too big for my sidebar width and 3 is too small (it has to add up to 12).
<div class="col-md-8">
<div class="col-md-4">
I tried this but it doesn't work:
<div class="col-md-8.5">
<div class="col-md-3.5">
Is there another way to get a similar outcome?
Thanks for your help!
To expand on #isherwood's answer, here is the complete code for creating custom -sm- widths in Bootstrap 3.3
In general you want to search for an existing column width (say col-sm-3) and copy over all the styles that apply to it, including generic ones, over to your custom stylesheet where you define new column widths.
.col-sm-3half, .col-sm-8half {
position: relative;
min-height: 1px;
padding-right: 15px;
padding-left: 15px;
}
#media (min-width: 768px) {
.col-sm-3half, .col-sm-8half {
float: left;
}
.col-sm-3half {
width: 29.16666667%;
}
.col-sm-8half {
width: 70.83333333%;
}
}
For a 12 columns grid, if you want to add half of a column (4,16667%) to each column width. This is what you do.
For example, for col-md-X, define .col-md-X-5 with the following values.
.col-md-1-5 { width: 12,5%; } // = 8,3333 + 4,16667
.col-md-2-5 { width: 20,83333%; } // = 16,6666 + 4,16667
.col-md-3-5 { width: 29,16667%; } // = 25 + 4,16667
.col-md-4-5 { width: 37,5%; } // = 33,3333 + 4,16667
.col-md-5-5 { width: 45,83333%; } // = 41,6667 + 4,16667
.col-md-6-5 { width: 54,16667%; } // = 50 + 4,16667
.col-md-7-5 { width: 62,5%; } // = 58,3333 + 4,16667
.col-md-8-5 { width: 70,83333%; } // = 66,6666 + 4,16667
.col-md-9-5 { width: 79,16667%; } // = 75 + 4,16667
.col-md-10-5 { width: 87,5%; } // = 83,3333 + 4,16667
.col-md-11-5 { width: 95,8333%; } // = 91,6666 + 4,16667
I rounded certain values.
Secondly, to avoid copying css code from the original col-md-X, use them in the class declaration. Be careful that they should be added before your modified ones. That way, only the width gets override.
<div class="col-md-2 col-md-2-5">...</div>
<div class="col-md-5">...</div>
<div class="col-md-4 col-md-4-5">...</div>
Finally, don't forget that the total should not exceed 12 columns, which total 100%.
I hope it helps!
You could certainly create your own classes:
.col-md-3point5 {width: 28.75%}
.col-md-8point5 {width: 81.25%;}
I'd do this before I'd mess with the default columns. You may want to use those inside these.
You'd probably also want to put those inside a media query statement so that they only apply for larger-than-mobile screen sizes.
Bootstrap 4.1+ version of Antoni's answer:
The Bootstrap mixin is now #include make-col($size, $columns: $grid-columns)
.col-md-8half {
#include make-col-ready();
#include media-breakpoint-up(md) {
#include make-col(8.5);
}
}
.col-md-3half {
#include make-col-ready();
#include media-breakpoint-up(md) {
#include make-col(3.5);
}
}
Source:
Official documentation
Bootstrap 4 Sass Mixins [Cheat sheet with examples]
You can use Bootstrap's own column mixins make-xx-column():
.col-md-8half {
.make-md-column(8.5);
}
.col-md-3half {
.make-md-column(3.5);
}
you can customize bootstrap stylesheet, as in:
.col-md-8{
width: /*as you wish*/;
}
Then, set the media query for that too, as in:
#media screen and (max-width:768px){
.col-md-8{
width:99%;
}
}
Does bootstrap 2.0 have any helpers to make .span1, .span2 .... .span12 equal height. I've nested this type of html
<div class='container'>
<div class='row'>
<div class='span2'>
<div class='well'>
XXXX
</div>
</div>
<div class='span2'>
<div class='well'>
XXXX
XXXX
</div>
</div>
<div class='span2'>
<div class='well'>
XXXX
XXXX
XXXX
</div>
</div>
</div>
</div>
I would like each well to end up the same height if possible?
Here's a responsive CSS solution, based on adding a large padding and an equally large negative margin to each column, then wrapping the entire row in in a class with overflow hidden.
.col{
margin-bottom: -99999px;
padding-bottom: 99999px;
background-color:#ffc;
}
.col-wrap{
overflow: hidden;
}
You can see it working at jsFiddle
Edit
In response to a question, here's a variation if you need equal height wells or equal height columns with rounded corners: http://jsfiddle.net/panchroma/4Pyhj/
Edit
In response to a question, here's the same technique in Bootstrap 3, same principle, just update the class names in the Bootstap grid: http://jsfiddle.net/panchroma/bj4ys/embedded/result/
Try something like this (not very elegant, though):
$('.well').css({
'height': $('.well').height()
});
The jQuerys height() method returns the highest value when multiple elements are selected.
See the jsFiddle:
http://jsfiddle.net/4HxVT/
jQuery's height() method returns the value of the "first element in the set of matched elements". The answer in http://jsfiddle.net/4HxVT/ only works because the first element in the row is also the highest.
Here's another jQuery based solution:
http://www.filamentgroup.com/lab/setting_equal_heights_with_jquery/
(Via this answer: https://stackoverflow.com/a/526316/518535)
Expanding upon the answers already given, I have just solved this using jquery and underscore. The snippet below equalizes the height of my wells and alerts that appear on a given row, regardless of where the tallest one appears:
$('.well, .alert').height(function () {
var h = _.max($(this).closest('.row').find('.well, .alert'), function (elem, index, list) {
return $(elem).height();
});
return $(h).height();
});
$.fn.matchHeight = function() {
var max = 0;
$(this).each(function(i, e) {
var height = $(e).height();
max = height > max ? height : max;
});
$(this).height(max);
};
$('.match-height').matchHeight();
I solved this with a custom jQuery max plugin:
$.fn.max = function(selector) {
return Math.max.apply(null, this.map(function(index, el) { return selector.apply(el); }).get() );
}
Here content-box is my internal column element, content-container is the wrapper that contains the columns:
$('.content-box').height(function () {
var maxHeight = $(this).closest('.content-container').find('.content-box')
.max( function () {
return $(this).height();
});
return maxHeight;
})
The above solutions all work until you add nice bootstrap buttons! How do you position buttons I thought (yes, that was my problem).
I combined the CSS with the jquery answer from How might I force a floating DIV to match the height of another floating DIV?
After a bit of frigging I got this, which works with CSS although the buttons don't line up, and is fine with jQuery
Feel free to fix the CSS button line up bit :)
jQuery:
$.fn.equalHeights = function (px) {
$(this).each(function () {
var currentTallest = 0;
$(this).children().each(function (i) {
if ($(this).height() > currentTallest) {
currentTallest = $(this).height();
}
});
if (!px && Number.prototype.pxToEm) {
currentTallest = currentTallest.pxToEm(); //use ems unless px is specified
}
// for ie6, set height since min-height isn't supported
if ($.browser.msie && $.browser.version == 6.0) {
$(this).children().css({
'height': currentTallest
});
}
$(this).children().css({
'min-height': currentTallest + 40 // THIS IS A FRIG - works for jquery but doesn't help CSS only
});
});
return this;
};
$(document).ready(function() {
var btnstyle = {
position : 'absolute',
bottom : '5px',
left : '10px'
};
$('.btn').css(btnstyle);
var colstyle = {
marginBottom : '0px',
paddingBottom : '0px',
backgroundColor : '#fbf'
};
$('.col').css(colstyle);
$('.row-fluid').equalHeights();
});
CSS
.col {
margin-bottom: -99999px;
padding-bottom: 99999px;
background-color:#ffb;
position:relative;
}
.col-wrap {
overflow: hidden;
}
.btn{
margin-left:10px ;
}
p:last-child {
margin-bottom:20px ;
}
jsfiddle - http://jsfiddle.net/brianlmerritt/k8Bkm/
Here is my solution with 2 columns (adapt this to more columns is simple, just add more conditions).
Run on the load event to have the correct heights of all elements.
$(window).on('load', function () {
var left = $('.left');
var leftHeight = left.height();
var right = $('.right');
var rightHeight = right.height();
// Width like mobile, the height calculation is not needed
if ($(window).width() <= 751)
{
if (leftHeight > rightHeight) {
right.css({
'height': 'auto'
});
}
else {
left.css({
'height': 'auto'
});
}
return;
}
if (leftHeight > rightHeight) {
right.css({
'height': leftHeight
});
}
else {
left.css({
'height': rightHeight
});
}
});
<div class="row">
<div class="span4 left"></div>
<div class="span8 right"></div>
</div>