feat(app): add responsive utility attributes by screen size (#11228)

- moves breakpoint mixins to the ionic.mixins file
- adds responsive attributes for text alignment, transform, and
floating elements
- adds ability to turn these off so they don’t get added to the css
file using sass variables

references #10904
closes #10567
This commit is contained in:
Brandy Carney
2017-04-14 12:47:59 -05:00
committed by GitHub
parent f9012e18bb
commit cf24057183
8 changed files with 404 additions and 99 deletions

View File

@@ -2,6 +2,7 @@
// Globals
// --------------------------------------------------
@import "../../themes/ionic.globals";
@import "../../themes/ionic.mixins";
// Normalize
@@ -49,6 +50,36 @@ $h5-font-size: 1.8rem !default;
$h6-font-size: 1.6rem !default;
// Responsive Utilities
// --------------------------------------------------
/// @prop - Whether to include all of the responsive utility attributes
$include-responsive-utilities: true !default;
/// @prop - Whether to include all of the responsive text alignment attributes
$include-text-alignment-utilities: $include-responsive-utilities !default;
/// @prop - Whether to include all of the responsive text transform attributes
$include-text-transform-utilities: $include-responsive-utilities !default;
/// @prop - Whether to include all of the responsive float attributes
$include-float-element-utilities: $include-responsive-utilities !default;
// Screen Breakpoints
// --------------------------------------------------
/// @prop - The minimum dimensions at which your layout will change,
/// adapting to different screen sizes, for use in media queries
$screen-breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px
) !default;
// App Structure
// --------------------------------------------------
@@ -293,77 +324,128 @@ ion-footer {
// Text Alignment
// --------------------------------------------------
[text-left] {
text-align: left;
}
@if ($include-text-alignment-utilities == true) {
// Creates text alignment attributes based on screen size
@each $breakpoint in map-keys($screen-breakpoints) {
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
[text-center] {
text-align: center;
}
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
// Provide `[text-{bp}]` attributes for aligning the text based
// on the breakpoint
[text#{$infix}-center] {
// scss-lint:disable ImportantRule
text-align: center !important;
}
[text-right] {
text-align: right;
}
[text#{$infix}-justify] {
// scss-lint:disable ImportantRule
text-align: justify !important;
}
[text-start] {
text-align: start;
}
[text#{$infix}-start] {
// scss-lint:disable ImportantRule
text-align: start !important;
}
[text-end] {
text-align: end;
}
[text#{$infix}-end] {
// scss-lint:disable ImportantRule
text-align: end !important;
}
[text-justify] {
text-align: justify;
}
[text#{$infix}-left] {
// scss-lint:disable ImportantRule
text-align: left !important;
}
[text-nowrap] {
white-space: nowrap;
}
[text#{$infix}-right] {
// scss-lint:disable ImportantRule
text-align: right !important;
}
[text-wrap] {
white-space: normal;
[text#{$infix}-nowrap] {
// scss-lint:disable ImportantRule
white-space: nowrap !important;
}
[text#{$infix}-wrap] {
// scss-lint:disable ImportantRule
white-space: normal !important;
}
}
}
}
// Text Transformation
// --------------------------------------------------
[text-uppercase] {
text-transform: uppercase;
@if ($include-text-transform-utilities == true) {
// Creates text transform attributes based on screen size
@each $breakpoint in map-keys($screen-breakpoints) {
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
// Provide `[text-{bp}]` attributes for transforming the text based
// on the breakpoint
[text#{$infix}-uppercase] {
// scss-lint:disable ImportantRule
text-transform: uppercase !important;
}
[text#{$infix}-lowercase] {
// scss-lint:disable ImportantRule
text-transform: lowercase !important;
}
[text#{$infix}-capitalize] {
// scss-lint:disable ImportantRule
text-transform: capitalize !important;
}
}
}
}
[text-lowercase] {
text-transform: lowercase;
}
[text-capitalize] {
text-transform: capitalize;
}
// Float
// Float Elements
// --------------------------------------------------
[pull-left] {
float: left;
}
@if ($include-float-element-utilities == true) {
// Creates text transform attributes based on screen size
@each $breakpoint in map-keys($screen-breakpoints) {
$infix: breakpoint-infix($breakpoint, $screen-breakpoints);
[pull-right] {
float: right;
}
@include media-breakpoint-up($breakpoint, $screen-breakpoints) {
// Provide `[pull-{bp}]` attributes for floating the element based
// on the breakpoint
[pull#{$infix}-left] {
// scss-lint:disable ImportantRule
float: left !important;
}
[pull-start] {
float: left;
}
[pull#{$infix}-right] {
// scss-lint:disable ImportantRule
float: right !important;
}
[pull-end] {
float: right;
}
[pull#{$infix}-start] {
// scss-lint:disable ImportantRule
float: left !important;
}
[dir="rtl"] [pull-start] {
float: right;
}
[pull#{$infix}-end] {
// scss-lint:disable ImportantRule
float: right !important;
}
[dir="rtl"] [pull-end] {
float: left;
[dir="rtl"] [pull#{$infix}-start] {
// scss-lint:disable ImportantRule
float: right !important;
}
[dir="rtl"] [pull#{$infix}-end] {
// scss-lint:disable ImportantRule
float: left !important;
}
}
}
}

View File

@@ -0,0 +1,10 @@
import { Component } from '@angular/core';
import { RootPage } from '../pages/root-page/root-page';
@Component({
template: `<ion-nav [root]="root"></ion-nav>`
})
export class AppComponent {
root = RootPage;
}

View File

@@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { IonicApp, IonicModule } from '../../../../..';
import { AppComponent } from './app.component';
import { RootPage } from '../pages/root-page/root-page';
@NgModule({
declarations: [
AppComponent,
RootPage
],
entryComponents: [
RootPage
],
imports: [
BrowserModule,
IonicModule.forRoot(AppComponent, { statusbarPadding: true })
],
bootstrap: [IonicApp],
})
export class AppModule {}

View File

@@ -0,0 +1,5 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@@ -0,0 +1,137 @@
<ion-header>
<ion-toolbar>
<ion-title>Utilities</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding class="util-demo">
<ion-row class="text-align-row">
<ion-col col-4>
<div text-center>text-center</div>
</ion-col>
<ion-col col-4>
<div text-sm-center>text-sm-center</div>
</ion-col>
<ion-col col-4>
<div text-md-center>text-md-center</div>
</ion-col>
<ion-col col-4>
<div text-lg-center>text-lg-center</div>
</ion-col>
<ion-col col-4>
<div text-xl-center>text-xl-center</div>
</ion-col>
</ion-row>
<ion-row class="text-align-row">
<ion-col col-4>
<div text-nowrap>text-nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap</div>
</ion-col>
<ion-col col-4>
<div text-sm-nowrap>text-sm-nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap</div>
</ion-col>
<ion-col col-4>
<div text-md-nowrap>text-md-nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap</div>
</ion-col>
<ion-col col-4>
<div text-lg-nowrap>text-lg-nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap</div>
</ion-col>
<ion-col col-4>
<div text-xl-nowrap>text-xl-nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap nowrap</div>
</ion-col>
</ion-row>
<ion-row class="text-transform-row">
<ion-col col-4>
<div text-uppercase>text-uppercase</div>
</ion-col>
<ion-col col-4>
<div text-sm-uppercase>text-sm-uppercase</div>
</ion-col>
<ion-col col-4>
<div text-md-uppercase>text-md-uppercase</div>
</ion-col>
<ion-col col-4>
<div text-lg-uppercase>text-lg-uppercase</div>
</ion-col>
<ion-col col-4>
<div text-xl-uppercase>text-xl-uppercase</div>
</ion-col>
</ion-row>
<div class="float-elements-row">
<div pull-left>pull-left</div>
<div pull-sm-left>pull-sm-left</div>
<div pull-md-left>pull-md-left</div>
<div pull-lg-left>pull-lg-left</div>
<div pull-xl-left>pull-xl-left</div>
</div>
<div class="float-elements-row">
<div pull-right>pull-right</div>
<div pull-sm-right>pull-sm-right</div>
<div pull-md-right>pull-md-right</div>
<div pull-lg-right>pull-lg-right</div>
<div pull-xl-right>pull-xl-right</div>
</div>
<div class="float-elements-row">
<div pull-start>pull-start</div>
<div pull-sm-start>pull-sm-start</div>
<div pull-md-start>pull-md-start</div>
<div pull-lg-start>pull-lg-start</div>
<div pull-xl-start>pull-xl-start</div>
</div>
<div class="float-elements-row">
<div pull-end>pull-end</div>
<div pull-sm-end>pull-sm-end</div>
<div pull-md-end>pull-md-end</div>
<div pull-lg-end>pull-lg-end</div>
<div pull-xl-end>pull-xl-end</div>
</div>
<div class="float-elements-row" dir="rtl">
<div pull-start>pull-start</div>
<div pull-sm-start>pull-sm-start</div>
<div pull-md-start>pull-md-start</div>
<div pull-lg-start>pull-lg-start</div>
<div pull-xl-start>pull-xl-start</div>
</div>
<div class="float-elements-row" dir="rtl">
<div pull-end>pull-end</div>
<div pull-sm-end>pull-sm-end</div>
<div pull-md-end>pull-md-end</div>
<div pull-lg-end>pull-lg-end</div>
<div pull-xl-end>pull-xl-end</div>
</div>
</ion-content>
<style>
.util-demo div {
border: 1px solid #dedede;
padding: 5px;
display: block;
}
.util-demo .text-transform-row div {
background-color: lightblue;
}
.util-demo .text-align-row div {
background-color: lightpink;
overflow: hidden;
text-overflow: ellipsis;
}
.util-demo .float-elements-row {
border: none;
}
.util-demo .float-elements-row div {
background-color: lightyellow;
height: 40px;
}
</style>

View File

@@ -0,0 +1,8 @@
import { Component } from '@angular/core';
@Component({
templateUrl: 'root-page.html'
})
export class RootPage {
constructor() { }
}

View File

@@ -1,4 +1,5 @@
@import "../../themes/ionic.globals";
@import "../../themes/ionic.mixins";
// Responsive Mixins
// --------------------------------------------------
@@ -255,52 +256,3 @@
}
}
}
// Breakpoint Mixins
// ---------------------------------------------------------------------------------
// Breakpoint viewport sizes and media queries.
//
// Breakpoints are defined as a map of (name: minimum width), order from small to large:
//
// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)
//
// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.
// ---------------------------------------------------------------------------------
// Minimum breakpoint width. Null for the smallest (first) breakpoint.
//
// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// 576px
@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
$min: map-get($breakpoints, $name);
@return if($min != 0, $min, null);
}
// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash infront.
// Useful for making responsive utilities.
//
// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// "" (Returns a blank string)
// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// "-sm"
@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {
@return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}");
}
// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.
// Makes the @content apply to the given breakpoint and wider.
@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
$min: breakpoint-min($name, $breakpoints);
@if $min {
@media (min-width: $min) {
@content;
}
} @else {
@content;
}
}

View File

@@ -67,3 +67,92 @@
@warn "First value in `#{$map-name}` must start at 0, but starts at #{$first-value}.";
}
}
// Breakpoint Mixins
// ---------------------------------------------------------------------------------
// Breakpoint viewport sizes and media queries.
//
// Breakpoints are defined as a map of (name: minimum width), order from small to large:
//
// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)
//
// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.
// ---------------------------------------------------------------------------------
// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash infront.
// Useful for making responsive utilities.
//
// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// "" (Returns a blank string)
// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// "-sm"
@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {
@return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}");
}
// Minimum breakpoint width. Null for the smallest (first) breakpoint.
//
// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// 576px
@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {
$min: map-get($breakpoints, $name);
@return if($min != 0, $min, null);
}
// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.
// Makes the @content apply to the given breakpoint and wider.
@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {
$min: breakpoint-min($name, $breakpoints);
@if $min {
@media (min-width: $min) {
@content;
}
} @else {
@content;
}
}
// Maximum breakpoint width. Null for the largest (last) breakpoint.
// The maximum value is calculated as the minimum of the next one less 0.1.
//
// >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// 767px
@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {
$next: breakpoint-next($name, $breakpoints);
@return if($next, breakpoint-min($next, $breakpoints) - 1px, null);
}
// Name of the next breakpoint, or null for the last breakpoint.
//
// >> breakpoint-next(sm)
// md
// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))
// md
// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl))
// md
@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {
$n: index($breakpoint-names, $name);
@return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);
}
// Media of at most the maximum breakpoint width. No query for the largest breakpoint.
// Makes the @content apply to the given breakpoint and narrower.
@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {
$max: breakpoint-max($name, $breakpoints);
@if $max {
@media (max-width: $max) {
@content;
}
} @else {
@content;
}
}