├── LICENSE ├── README.md └── _angled-edges.scss /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Joseph Fusco 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angled Edges :triangular_ruler: [![Build Status](https://travis-ci.org/josephfusco/angled-edges.svg?branch=master)](https://travis-ci.org/josephfusco/angled-edges) [![Bower version](https://badge.fury.io/bo/angled-edges.svg)](https://badge.fury.io/bo/angled-edges) [![npm version](https://badge.fury.io/js/angled-edges.svg)](https://badge.fury.io/js/angled-edges) 2 | 3 | A Sass mixin for creating angled edges on sections by dynamically encoding SVGs. 4 | 5 | Need angled edges in regular CSS? Check out the [Angled Edges Generator](https://angled-edges-generator.josephfus.co). 6 | 7 | angled edge 8 | 9 | ## Usage 10 | 11 | Import partial: 12 | ```scss 13 | @import "angled-edges"; 14 | ``` 15 | 16 | This mixin has 3 required parameters: **location**, **hypotenuse**, **fill** 17 | ```scss 18 | @include angled-edge($location, $hypotenuse, $fill); 19 | ``` 20 | 21 | The main mixin creates an svg right triangle that is encoded, set as a background image of a pseudo element, and absolutely positioned. 22 | 23 | ### Examples 24 | 25 | https://codepen.io/fusco/pen/mzymKm 26 | 27 | ## Options 28 | 29 | | Parameter | Description | 30 | | ----------| ----------- | 31 | | `$location` | Location of shape relative to parent element | 32 | | `$hypotenuse` | Side of the right triangle that the hypotenuse is on | 33 | | `$fill` | Fill color of triangle | 34 | | `$height` | Optional - Height of triangle - Accepts a unitless integer that is equivalent to height in `px` | 35 | | `$width` | Optional - Width of triangle - Accepts a unitless integer that is equivalent to width in `px` (If nothing is passed triangle will span to a 100% fluid width) | 36 | 37 | ## Upgrading from 1.x 38 | 39 | Version 2 now defaults with a fluid width of 100%. Since this is the preferred value, width and height parameters have switched order with height now being first. This allows for easier usage where 40 | ```scss 41 | @include angled-edge('outside bottom', 'lower right', 150); 42 | ``` 43 | now means a 150px tall with at a default of 100% width. If a fluid width is not needed, you can still pass in a unitless width like in 1.x. If you previously were using `background-size` to manipulate the shape, you will need to remove this property as the mixin also uses this to assist with making the shape full-width. 44 | 45 | ## Demo 46 | 47 | [https://angled-edges.josephfus.co](http://angled-edges.josephfus.co) 48 | 49 | ## Browser Support 50 | 51 | Anywhere SVG is supported. 52 | 53 | - [x] IE 9+ 54 | - [x] Edge 55 | - [x] Firefox 56 | - [x] Chrome 57 | - [x] Safari 58 | - [x] Opera 59 | - [x] iOS Safari 60 | - [x] Opera Mini 61 | - [x] Android Browser 62 | - [x] Chrome for Android 63 | 64 | ## Project Ports 65 | 66 | + [Stylus Angled Edges](https://github.com/OlegWock/stylus-angled-edges) 67 | -------------------------------------------------------------------------------- /_angled-edges.scss: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------------- 2 | // Angled Edges v2.0.0 (https://github.com/josephfusco/angled-edges) 3 | // Copyright 2017 Joseph Fusco 4 | // Licensed under MIT (https://github.com/josephfusco/angled-edges/blob/master/LICENSE) 5 | //------------------------------------------------------------------------------------- 6 | 7 | /// Replace `$search` with `$replace` in `$string`. 8 | /// 9 | /// @author Hugo Giraudel 10 | /// @link http://www.sassmeister.com/gist/1b4f2da5527830088e4d 11 | /// 12 | /// @param {String} $string - Initial string 13 | /// @param {String} $search - Substring to replace 14 | /// @param {String} $replace ('') - New value 15 | /// @return {String} Updated string 16 | /// 17 | @function ae-str-replace($string, $search, $replace: '') { 18 | $index: str-index($string, $search); 19 | 20 | @if $index { 21 | @return str-slice($string, 1, $index - 1) + $replace + ae-str-replace(str-slice($string, $index + str-length($search)), $search, $replace); 22 | } 23 | 24 | @return $string; 25 | } 26 | 27 | /// Encode SVG to use as background. 28 | /// 29 | /// @param {String} $string 30 | /// @return {String} Encoded svg data 31 | /// 32 | @function ae-svg-encode($string){ 33 | $result: ae-str-replace($string, '', '%3E'); 38 | 39 | @return 'data:image/svg+xml,' + $result; 40 | } 41 | 42 | /// Outputs pseudo content for main mixin. 43 | /// 44 | /// @author Joseph Fusco 45 | /// 46 | /// @param {String} $location 47 | /// @param {Number} $height 48 | /// @output psuedo content 49 | /// 50 | @mixin ae-pseudo($wedge, $height, $width) { 51 | background-image: url($wedge); 52 | background-position: center center; 53 | background-repeat: no-repeat; 54 | 55 | // full width wedge - needed as Firefox ignores preserveAspectRatio="none" in this case 56 | @if ($width == null) { 57 | background-size: 100% 100%; 58 | } 59 | 60 | content: ''; 61 | height: $height * 1px; 62 | left: 0; 63 | position: absolute; 64 | right: 0; 65 | width: 100%; 66 | z-index: 1; 67 | } 68 | 69 | /// Attatches an svg wedge shape to an element. 70 | /// 71 | /// @author Joseph Fusco 72 | /// 73 | /// @param {String} $location - 'inside top', 'outside top', 'inside bottom', 'outside bottom' 74 | /// @param {String} $hypotenuse - 'upper left', 'upper right', 'lower left', 'lower right' 75 | /// @param {Color} $fill 76 | /// @param {Number} $height 77 | /// @param {Number} $width 78 | /// @output '::before' and/or '::after' with svg background image 79 | /// 80 | @mixin angled-edge($location, $hypotenuse, $fill, $height: 100, $width: null) { 81 | 82 | position: relative; 83 | 84 | $points: ( 85 | 'upper left': '0,#{$height} #{$width},#{$height} #{$width},0', 86 | 'upper right': '0,#{$height} #{$width},#{$height} 0,0', 87 | 'lower left': '0,0 #{$width},#{$height} #{$width},0', 88 | 'lower right': '0,0 #{$width},0 0,#{$height}' 89 | ); 90 | 91 | // full width wedge 92 | @if ($width == null) { 93 | $points: ( 94 | 'upper left': '0,#{$height} 100,#{$height} 100,0', 95 | 'upper right': '0,#{$height} 100,#{$height} 0,0', 96 | 'lower left': '0,0 100,#{$height} 100,0', 97 | 'lower right': '0,0 100,0 0,#{$height}' 98 | ); 99 | } 100 | 101 | // ensure $fill color is using rgb() 102 | $fill-rgb: 'rgb(' + round(red($fill)) + ',' + round(green($fill)) + ',' + round(blue($fill)) + ')'; 103 | 104 | // capture alpha component of $fill to use with fill-opacity 105 | $fill-alpha: alpha($fill); 106 | 107 | $wedge: ''; 108 | 109 | // full width wedge 110 | @if ($width == null) { 111 | $wedge: ''; 112 | } 113 | 114 | $encoded-wedge: ae-svg-encode($wedge); 115 | 116 | @if ($location == 'inside top') { 117 | &::before { 118 | @include ae-pseudo($encoded-wedge, $height, $width); 119 | top: 0; 120 | } 121 | } @else if ($location == 'outside top') { 122 | &::before { 123 | @include ae-pseudo($encoded-wedge, $height, $width); 124 | top: -$height * 1px; 125 | } 126 | } @else if ($location == 'inside bottom') { 127 | &::after { 128 | @include ae-pseudo($encoded-wedge, $height, $width); 129 | bottom: 0; 130 | } 131 | } @else if ($location == 'outside bottom') { 132 | &::after { 133 | @include ae-pseudo($encoded-wedge, $height, $width); 134 | bottom: -$height * 1px; 135 | } 136 | } @else { 137 | @error 'Invalid argument for $location - must use: `inside top`, `outside top`, `inside bottom`, `outside bottom`'; 138 | } 139 | 140 | @if (map-has-key($points, $hypotenuse) == false) { 141 | @error 'Invalid argument for $hypotenuse - must use: `upper left`, `upper right`, `lower left`, `lower right`'; 142 | } 143 | } 144 | --------------------------------------------------------------------------------