<!DOCTYPE html>
<html class="no-js" ng-app="cssBoxModel">
  <head>
    <meta charset="utf-8">
    <title>cssBoxModel</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.2/angular.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.2/angular-animate.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.2/angular-sanitize.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.13/angular-ui-router.min.js"></script>
    <script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/97151/ui.slider.js"></script>
  </head>
  <body>
    <div ui-view="diagram"></div>
  </body>
</html>
@import "bourbon";
@import "neat";

$color-margin: #DE6A63;
$color-padding: #C5D936;
$color-content: #63BCF8;
$color-border: #F8CC63;
$color-box-sizing: #8ADFE0;

$color-bg: #242930;
$color-dark-light: #343434;
$color-dark-lighter: #444;
$color-dark-lightest: #777;
$color-body: #808386;
$color-white: #FFFFFF;


$knob-size: 20px;
$knob-border-width: 3px;

$boxes: (content: $color-content,
         padding: $color-padding,
         border: $color-border,
         margin: $color-margin,
         box-sizing: $color-box-sizing,
         generated-size: $color-content);

$sliders: content, padding, border, margin;

$lg: new-breakpoint(min-width 1245px 7);
$md: new-breakpoint(min-width 950px);
$sm: new-breakpoint(min-width 790px 6);
$xxs: new-breakpoint(max-width 550px);

// Site-wide base styles.
// Setting root sizes and base styles.
html {
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
  @include rootsize;
}

body {
  background-color: $color-bg;
  color: $color-body;
  overflow-x: hidden;
  font-family: unquote(map-get($bodytype, font-family));
  font-style: normal;
  font-weight: map-get($bodytype, regular);
  line-height: 2rem;
  @include fontsize(zeta, all);
}

main {
  margin: 20px auto;
  padding: 0 20px;
  @include outer-container;
  @include media($xxs) {
    padding: 0;
    margin-top: 10px;
  }
}

.box-model {
  @include media($sm) {
    @include span-columns(6);
  }
  @include media($md) {
    @include span-columns(7);
  }
  #content, #generated-size {
    @include media($lg) {
      @include span-columns(4 of 7);
    }
  }
  #generated-size {
    @include media($lg) {
      @include span-columns(3 of 7);
      @include omega;
    }
  }
}

.controls {
  @include media($sm) {
    @include span-columns(6);
  }
  @include media($md) {
    @include span-columns(5);
  }
}


/* ************************************************************ */

// BOX Style mixins
// --------------------------------------

@mixin box-property-labels($position) {
  .box-property-vertical {
    left: $position;
  }
  .box-property-horizontal {
    top: $position;
  }
}

@mixin stagger-labels($position) {
  .box-property-vertical {
    left: $position;
  }
  .box-property-horizontal {
    top: $position;
  }
}

%hover-opacity {
  opacity: 1;
}

@mixin box-styles($color, $border-style, $position-outer:false, $position:0) {
  background: $color;
  border: 1px $border-style lighten($color-body, 45%);
  text-shadow: 0px 1px 1px transparentize(lighten($color, 20%), 0.3);
  span::before,
  span::after {
    color: darken($color, 40%);
  }
  &:hover {
    background-color: $color !important;
    @if position-outer {
      .box-property-vertical,
      .box-property-horizontal {
        @extend %hover-opacity;
        opacity: 1;
      }
    }
  }
  @if $position-outer {
    @include stagger-labels($position);
  }
}



/*****************************************
* CONTROL STYLES
******************************************/

// Fieldset/Legend
// ---------------------------------------

fieldset {
  border: 1px solid $color-dark-light;
  padding: 0 10px 5px;
}

#generated-size fieldset {
  min-height: 114px;
}

legend {
  text-transform: uppercase;
  font-weight: 300;
  font-size: 1.3em;
}

@each $property, $color in $boxes {
  ##{$property} {
    legend {
      color: $color;
    }
  }
}

label, .value, .toggle-text {
  font-size: 60%;
  display: inline-block;
  white-space: nowrap;
  font-family: unquote(map-get($bodytype, font-family));
  letter-spacing: 1.5px;
}

.control-set {
  margin-top: 20px;
  width: 100%;
  label, .toggle-text {
    width: 25%;
    text-transform: uppercase;
  }
  .slider {
    width: 65%;
    @include media($md) {
      width: 55%;
    }
    @include media($lg) {
      width: 63%;
    }
  }
  .value {
    width: 7%;
    text-align: right;
  }
}

.box-model #content label {
  width: 25%;
  @include media($md) {
    width: 22%;
  }
}

#box-sizing  label {
  width: 40%;
}



// Radio Button
// ---------------------------------------
.radio {
  position: relative;
  margin: 0 1rem 0 0;
  cursor: pointer;
  &::before,
  &::after {
    @include transition(all 0.3s ease-in-out);
    content: "";
    position: absolute;
    top: -0.2rem;
    left: -0.2rem;
    z-index: 1;
    width: $knob-size;
    height: $knob-size;
    background: $color-dark-light !important;
    border-radius: 50%;
  }
  &:checked,
  &.ng-valid-parse {
    &::before {
      @include transform(scale(0, 0));
      border-color: $color-box-sizing !important;
      border-width: $knob-border-width !important;
    }
    &::after {
      border: $knob-border-width solid $color-box-sizing !important;
      background: $color-bg !important;
    }
  }
}

// Range Sliders
// ---------------------------------------
slider, [slider] {
  display: inline-block;
  position: relative;
  height: 7px;
  width: 63%;
  vertical-align: middle;
  margin: 5px;
  div {
    white-space: nowrap;
    position: absolute;
    &.handle {
      border: $knob-border-width solid;
      cursor: pointer;
      width: $knob-size;
      height: $knob-size;
      top: -8px;
      background-color: $color-bg;
      z-index: 2;
      border-radius: 100%;
      &::after {
        content: '';
        width: 8px;
        height: 8px;
        position: absolute;
        left: 6px;
        border-radius: 100%;
        background-color: transparent;
      }
      &.active::after {
        background-color: transparent;
      }
    }
    &.bar {
      width: 100%;
      height: 100%;
      border-radius: 7px;
      background: $color-dark-lighter;
      overflow: hidden;
      .selection {
        width: 0;
        height: 100%;
      }
    }
    // TODO: remove Bubble functionality from slider directive
    &.bubble {
      display: none;
      cursor: default;
      top: -22px;
      padding: 1px 3px;
      font-size: 0.7em;
      &.active {
        display: inline-block;
      }
      &.limit {
        color: $color-dark-lightest;
      }
    }
  }
}

.bubble.value.low.ng-binding.active {
  display: none;
}

.bar-color {
  height: 20px;
  border-right: 3px solid;
  box-sizing: content-box;
}

@each $property in $sliders {
  ##{$property} {
    .slider-selection, .bar-color {
      background-color: unquote(map-get($boxes, #{$property}));
    }
    .bar-color,
    .handle {
      border-color: unquote(map-get($boxes, #{$property}));
    }
  }
}

@media (min-width: 951px) and (max-width: 1244px) {
  .controls {
    .sliders label {
      display: block;
      line-height: 1rem;
      &:first-of-type {
          margin-top: 8px;
      }
    }
    slider, [slider]  {
      width: 87%;
     }
  }
}

// Toggle
// ---------------------------------------
.toggle {
    display: none;
    &, &::after, &::before, & *, & *::after, & *::before, & + .toggle-control {
        box-sizing: border-box;
        &::selection {
            background: none;
        }
    }
    + .toggle-control {
        outline: 0;
        top: 10px;
        margin-bottom: 8px;
        width: 52px;
        position: relative;
        cursor: pointer;
        user-select: none;
        padding: 3px;
        @include transition(all 0.3s ease-in-out);
        background: $color-bg;
        border: $knob-border-width/2 solid $color-dark-lighter;
        border-radius: 2em;
        &::after, &::before {
            position: relative;
            display: block;
            content:"";
            width: $knob-size;
            height: $knob-size;
        }
        &::after {
            left: 0;
            @include transition(all 0.3s ease-in-out);
            background: $color-dark-light;
            border-radius: 50%;
        }
        &::before {
            display: none;
        }
    }
    &:checked {
        + .toggle-control {
            border: $knob-border-width/2 solid $color-dark-lighter;
            &::after {
                left: 50%;
                height: $knob-size;
                width: $knob-size;
                background: $color-bg;
                border: $knob-border-width solid $color-content;
            }
        }
    }
}
.toggle-text {
    vertical-align: text-bottom;
    margin-left: 5px;
}


// Generated Size Change Animation (ng-animate)
// ---------------------------------------
.generated-direction {
  display: inline-block;
  width: 150px;
}

.generated-width,
.generated-height {
  font-size: 60%;
  white-space: nowrap;
  font-family: unquote(map-get($bodytype, font-family));
  letter-spacing: 1.5px;
  text-transform: uppercase;
  line-height: 3rem;
  @include media($sm) {
    line-height: 2rem;
  }
  .changes {
    text-transform: none;
    display: inline-block;
    line-height: 25px;
    padding: 0 5px;
    background: #2F353E;
    border-radius: 3px;
    color: $color-content;
    @include transition(color 0.4s ease-in-out, background 0.4s ease-in-out);
    &[class*="-add"] {
      color: darken($color-content, 45%);
      background: $color-content;
    }
    &.highlight {
      &.ng-enter {
        background: #2F353E;
        color: $color-content;
        &.ng-enter-active {
          color: darken($color-content, 45%);
          background: $color-content;
        }
      }
      &.ng-leave {
        color: darken($color-content, 45%);
        background: $color-content;
        &.ng-leave-active {
          background: #2F353E;
          color: $color-content;
        }
      }
    }
  }
}
/*****************************************
* DIAGRAM STYLES
******************************************/

#diagram {
  margin-left: 5px;
  clear: left;
  padding-top: $gutter;
}

.box {
  position: relative;
  &:hover {
    .box-property {
      background: $color-white;
    }
    .box-property-vertical,
    .box-property-horizontal {
      opacity: 0;
    }
  }
}

.box-property {
  font-family: unquote(map-get($monospacetype, font-family));
  @include transition(width 0.3s linear, height 0.3s linear);
  position: absolute;
}

.box-padding {
  @include box-styles($color-padding, dashed, true, 40%);
}
.box-border {
  @include box-styles($color-border, solid, true, 50%);
}
.box-margin {
  @include box-styles($color-margin, dashed, true, 60%);
/** To Decode this SVG image, paste the css here: www.svgeneration.com/tools/base-64-decoder */

background-color: #de6a63;
background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc3JyBoZWlnaHQ9JzE0JyB2aWV3Qm94PScwIDAgNSAxMCc+Cgk8cmVjdCB3aWR0aD0nMTEwJScgeD0nLTUlJyB5PSctNSUnIGhlaWdodD0nMTEwJScgZmlsbD0nI2RlNmE2MycvPgoJPGxpbmUgeDE9JzcnIHkxPScxJyB4Mj0nLTInIHkyPScxMCcgc3Ryb2tlPScjZWVhYWE1JyBzdHJva2Utd2lkdGg9JzAuMjknLz4KCTxsaW5lIHgxPSc3JyB5MT0nNicgeDI9Jy0yJyB5Mj0nMTUnIHN0cm9rZT0nI2VlYWFhNScgc3Ryb2tlLXdpZHRoPScwLjI5Jy8+Cgk8bGluZSB4MT0nNycgeTE9Jy00JyB4Mj0nLTInIHkyPSc1JyBzdHJva2U9JyNlZWFhYTUnIHN0cm9rZS13aWR0aD0nMC4yOScvPgo8L3N2Zz4=');

}

.box-inner {
  @include box-styles($color-content, solid);
  text-align: center;
  &::before {
    color: darken($color-content, 35%);
    content: attr(data-width) " x " attr(data-height);
    position: absolute;
    left: 0;
    top: 50%;
    margin-top: .5em;
    width: 100%;
    font-size: .75em;
    white-space: nowrap;
  }
}



// Box-Property Main Labels
// ---------------------------------------
.property-label {
  font-family: unquote(map-get($headingtype, font-family));
  text-transform: uppercase;
  font-weight: 400;
  letter-spacing: 2px;
  font-size: 11px;
  top: -6px;
  @include media($sm) {
    top: -12px;
  }

  left: 5px;
  position: relative;
  &#property-label-padding {
    color: darken($color-padding, 15%);
  }
  &#property-label-border {
    color: darken($color-border, 28%);
  }
  &#property-label-margin {
    color: darken($color-margin, 20%);
  }
  &#property-label-content {
    color: darken($color-content, 20%);
    float: left;
    top: -6px;
    @include media($sm) {
    top: -8px;
    }
  }
}

#padding-v::before {
  top: -8px;
}

%box-property-position {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2000;
  &::before, &::after {
    position: absolute;
    font-size: 0.75em;
    text-align: center;
  }
}

%property-vertical {
  left: -0.5em;
  width: 100%;
}

%property-horizontal {
  margin-top: -0.65em;
  width: 2em;
  height: 100%;
}

$properties: zip(vertical horizontal, height width, top left, bottom right, -0.5em -1em);

@each $direction, $dimension, $offset-before, $offset-after, $amount in $properties {
  .box-property-#{$direction} {
     @extend %box-property-position;
    #{$dimension}: 100%;
    &::before {
      content:attr(data-#{$offset-before});
      @extend %property-#{$direction};
      #{$offset-before}: $amount;
    }
    &::after {
      content: attr(data-#{$offset-after});
      @extend %property-#{$direction};
      #{$offset-after}: $amount;
    }
  }
}
// code on GitHub
// https://github.com/carolineartz/learning-box-model
// http://car.oline.codes

// rebound of this jQuery demo https://codepen.io/guyroutledge/pen/hgpez

angular.module('cssBoxModel', ['ngAnimate', 'ngSanitize', 'ui.router','ui.slider'])


.config(['$stateProvider', '$locationProvider', function($stateProvider, $locationProvider) {
    $stateProvider.state('home', {
            url: '',
      			controller: 'MainCtrl',
      			views: {
              'diagram': {
            		templateUrl: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/97151/main.html',
                controller: 'MainCtrl'
              }
            }
            
        });
}])

.directive('labelPositionV', function() {
    return {
        restrict: 'AE',
        scope: {},
        link: function(scope, element, attrs, ctrl) {
            var id = attrs.id;
            attrs.$observe('labelPositionTop', function(value) {
                var styleTop = "<style> #" + id + "::before{top:" + ((value / 2.8) - 12) + "px;}</style>";
                angular.element(document).find('head').append(styleTop);
            });
            attrs.$observe('labelPositionBottom', function(value) {
                var styleBottom = "<style> #" + id + "::after{bottom:" + ((value / 3) - 13) + "px;}</style>";
                angular.element(document).find('head').append(styleBottom);
            });
        }
    };
})

.directive('labelPositionH', function() {
    return {
        restrict: 'AE',
        scope: {},
        link: function(scope, element, attrs, ctrl) {
            var id = attrs.id;
            attrs.$observe('labelPositionRight', function(value) {
                var styleRight = "<style> #" + id + "::after{right:" + (1*((value / 2.8) - 12)) + "px;}</style>";
                angular.element(document).find('head').append(styleRight);
            });
            attrs.$observe('labelPositionLeft', function(value) {
                var styleLeft = "<style> #" + id + "::before{left:" + (1*((value / 3)-12)) + "px;}</style>";
                angular.element(document).find('head').append(styleLeft);
            });

        }
    };
});

// Controller
// **********************************************************************

var app = angular.module('cssBoxModel');

app.controller('MainCtrl', function ($scope) {

    //models: default adjustable values
    $scope.padding = {
        top: 20,
        right: 20,
        bottom: 20,
        left: 20,
        v: function () {
            return this.top + this.bottom;
        },
        h: function () {
            return this.right + this.left;
        }
    };

    $scope.border = {
        top: 15,
        right: 15,
        bottom: 15,
        left: 15,
        v: function () {
            return this.top + this.bottom;
        },
        h: function () {
            return this.right + this.left;
        }
    };

    $scope.margin = {
        top: 20,
        right: 20,
        bottom: 20,
        left: 20,
        v: function () {
            return this.top + this.bottom;
        },
        h: function () {
            return this.right + this.left;
        }
    };

    $scope.box = {
        sizing: 'content-box'
    };

    $scope.dimensions = {
        width: 220,
        height: 220
    };

    $scope.innerContent = {
        width: getInnerWidth(),
        height: getInnerHeight()
    };

    $scope.generatedIncludeMargin = false;

    $scope.generatedBoxDimensions = {
        width: getGeneratedBoxDimensionsWidth(),
        height: getGeneratedBoxDimensionsHeight()
    };

    $scope.checkIncludeMargin = function() {
      $scope.generatedBoxDimensions.width = getGeneratedBoxDimensionsWidth();
      $scope.generatedBoxDimensions.height = getGeneratedBoxDimensionsHeight();
    };


    //actual applied style values
    $scope.boxPosition = {
        left: 50,
        top: 56
    };

    $scope.styleMargin = {
        width: 300,
        height: 300,
        top: -50,
        left: -50
    };

    $scope.styleBorder = {
        width: 260,
        height: 260,
        top: -30,
        left: -30
    };

    $scope.stylePadding = {
        width: 242,
        height: 242,
        top: -20,
        left: -20
    };

    //watch for changes applied to sliders and calculate rendered styles
    $scope.$watch(function () {
        $scope.boxPosition.top = calcBoxPositionTop() + 6;
        $scope.boxPosition.left = calcBoxPositionLeft();

        //Margin Styles
        $scope.styleMargin.width = $scope.margin.h() + $scope.styleBorder.width;
        $scope.styleMargin.height = $scope.margin.v() + $scope.styleBorder.height;
        $scope.styleMargin.top = -calcBoxPositionTop();
        $scope.styleMargin.left = -calcBoxPositionLeft();

        //Border Styles
        $scope.styleBorder.width = $scope.border.h() + $scope.stylePadding.width;
        $scope.styleBorder.height = $scope.border.v() + $scope.stylePadding.height;
        $scope.styleBorder.top = -($scope.border.top + $scope.padding.top);
        $scope.styleBorder.left = -($scope.border.left + $scope.padding.left);

        //Padding Styles
        $scope.stylePadding.width = $scope.padding.h() + getInnerWidth() + 2;
        $scope.stylePadding.height = $scope.padding.v() + getInnerHeight() + 2;
        $scope.stylePadding.top = -$scope.padding.top;
        $scope.stylePadding.left = -$scope.padding.left;

        //Inner Content Styles- based on box-sizing
        $scope.innerContent.width = getInnerWidth();
        $scope.innerContent.height = getInnerHeight();

        //Generated Dimensions- based on box-sizing
        $scope.generatedBoxDimensions.width = getGeneratedBoxDimensionsWidth();
        $scope.generatedBoxDimensions.height = getGeneratedBoxDimensionsHeight();
    });

    function getInnerWidth() {
        var width;
        if ($scope.box.sizing === 'border-box') {
            width =  $scope.dimensions.width -
                     $scope.border.h() -
                     $scope.padding.h();
        } else {
            width =  $scope.dimensions.width;
        }
        return (width > 0) ? width : 0;
    }

    function getInnerHeight() {
        var height;
        if ($scope.box.sizing === 'border-box') {
            height = $scope.dimensions.height -
                     $scope.border.v() -
                     $scope.padding.v();
        } else {
            height = $scope.dimensions.height;
        }
        return (height > 0) ? height : 0;
    }


    //if padding + border > dimension, return (padding + border - dimension) [+ margin]
    function getGeneratedBoxDimensionsWidth() {
        var width;
        if ($scope.box.sizing === 'border-box') {
            width = (getInnerWidth() === 0) ? calcPaddingBorderWidth() : $scope.dimensions.width;
        } else {
            width = $scope.dimensions.width + calcPaddingBorderWidth();
        }
        return ($scope.generatedIncludeMargin) ? width + $scope.margin.h() : width;
    }

    function getGeneratedBoxDimensionsHeight() {
        var height;
        if ($scope.box.sizing === 'border-box') {
            height = (getInnerHeight() === 0) ? calcPaddingBorderHeight() : $scope.dimensions.height;
        } else {
            height = $scope.dimensions.height + calcPaddingBorderHeight();
        }
        return ($scope.generatedIncludeMargin) ? height + $scope.margin.v() : height;
    }

    /*
     * Private: Helpers
     */
    function calcBoxPositionTop() {
        return $scope.margin.top + $scope.border.top + $scope.padding.top;
    }

    function calcBoxPositionLeft() {
        return $scope.margin.left + $scope.border.left + $scope.padding.left;
    }

    function calcPaddingBorderWidth() {
        return $scope.padding.h() + $scope.border.h();
    }

    function calcPaddingBorderHeight() {
        return $scope.padding.v() + $scope.border.v();
    }

});

External CSS

  1. https://s3-us-west-2.amazonaws.com/s.cdpn.io/97151/import-bourbon-neat.scss
  2. https://s3-us-west-2.amazonaws.com/s.cdpn.io/97151/import-sassline.scss
  3. https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400|Source+Code+Pro:300,400

External JavaScript

This Pen doesn't use any external JavaScript resources.