SOURCE

console 命令行工具 X clear

                    
>
console
/*
1. 在 modal 弹出来的时候,我们要给 body 一个 overflow:hidden 属性,禁止屏幕滚动
2. modal-backdrop 是单独的,就是下面的阴影
2. modal 是相对于浏览器定位的容器,
*/
(function(){
  function hide(toggler){
  	let target = document.querySelector(toggler.dataset.target);
    document.body.classList.remove('modal-open');
    let backdrop = document.querySelector('.modal-backdrop');
    backdrop.classList.remove('show');
    setTimeout(function(){
      backdrop.parentElement.removeChild(backdrop);
    }, 500);
    target.classList.remove('show');
    setTimeout(function(){
      target.style.display = 'none';
    }, 500);
  }
  function show(toggler){
    let target = document.querySelector(toggler.dataset.target);
    target.style.display = 'block';
    setTimeout(function(){
      target.classList.add('show');
    }, 0);
    document.body.classList.add('modal-open');
    let backdrop = document.createElement('div');
    backdrop.classList.add('modal-backdrop');
    backdrop.classList.add('fade');
    backdrop.onclick = function(){hide(toggler)};
		Array.prototype.forEach.call(target.querySelectorAll('[data-dismiss="modal"]'), function(btn){
      btn.onclick = function(){
        hide(toggler);
      };
    });
    document.body.appendChild(backdrop);
    setTimeout(function(){
      backdrop.classList.add('show');
    }, 0);
  }

  
  document.querySelector('[data-toggle="modal"]').onclick = function(){
    show(this);
  };
})();
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" style="">
  Launch demo modal
</button>

<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        ...
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary">Save changes</button>
      </div>
    </div>
  </div>
</div>
<div class="h-200vh">测试滚动</div>
.modal-open{
  overflow: hidden;// 工具类 用于禁用滚动
}
.modal{
  position: fixed;
  top: 0;right: 0; left: 0; bottom: 0;
  pointer-events: none;
  z-index: 1050;
  overflow: hidden;
  outline: 0;
  display: none;
  .modal-open &{
    overflow-x: hidden;
    overflow-y: auto;
  }
}

.modal-dialog{
  pointer-events: none;
  position: relative;
  margin: .5rem;
  pointer-events: none;
  .modal.fade &{
    transition: transform .5s ease;
    transform: translate(0, -125%);
  }
  .modal.fade.show &{
    transform: translate(0,0);
  }
}

.modal-content{
  position: relative;
  display: flex;
  flex-direction: column;
  pointer-events: auto;
  background: #fff;
  border-radius: .25rem;
  padding: .5rem 1rem;
  width: 20rem;
  max-width: 100%;
  margin: 2rem auto;
  .close{
    position: absolute;
    top: .5rem; right: 1rem;
  }
}

// modal 阴影
.modal-backdrop{
  position: fixed;
  left:0; right:0;top:0;bottom:0;
  z-index:1040;
  background:#000;
  &.fade{
    transition: opacity 1s ease;
    opacity: 0;
    &.show{
      opacity: .3;
    }
  }
}
/* 测试滚动禁用 */
.h-200vh{
  height: 200vh;
  background: yellowgreen;
}
/* 按钮美化 */
// Variables
//
// Variables should follow the `$component-state-property-size` formula for
// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs.


//
// Color system
//

// stylelint-disable
$white:    #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9ecef !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #6c757d !default;
$gray-700: #495057 !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black:    #000 !default;

$grays: () !default;
$grays: map-merge((
  "100": $gray-100,
  "200": $gray-200,
  "300": $gray-300,
  "400": $gray-400,
  "500": $gray-500,
  "600": $gray-600,
  "700": $gray-700,
  "800": $gray-800,
  "900": $gray-900
), $grays);

$blue:    #007bff !default;
$indigo:  #6610f2 !default;
$purple:  #6f42c1 !default;
$pink:    #e83e8c !default;
$red:     #dc3545 !default;
$orange:  #fd7e14 !default;
$yellow:  #ffc107 !default;
$green:   #28a745 !default;
$teal:    #20c997 !default;
$cyan:    #17a2b8 !default;

$colors: () !default;
$colors: map-merge((
  "blue":       $blue,
  "indigo":     $indigo,
  "purple":     $purple,
  "pink":       $pink,
  "red":        $red,
  "orange":     $orange,
  "yellow":     $yellow,
  "green":      $green,
  "teal":       $teal,
  "cyan":       $cyan,
  "white":      $white,
  "gray":       $gray-600,
  "gray-dark":  $gray-800
), $colors);

$primary:       $blue !default;
$secondary:     $gray-600 !default;
$success:       $green !default;
$info:          $cyan !default;
$warning:       $yellow !default;
$danger:        $red !default;
$light:         $gray-100 !default;
$dark:          $gray-800 !default;

$theme-colors: () !default;
$theme-colors: map-merge((
  "primary":    $primary,
  "secondary":  $secondary,
  "success":    $success,
  "info":       $info,
  "warning":    $warning,
  "danger":     $danger,
  "light":      $light,
  "dark":       $dark
), $theme-colors);

$input-btn-padding-x: .75rem;
$input-btn-padding-y: .375rem;
$input-btn-padding-x-sm: .5rem;
$input-btn-padding-y-sm: .25rem;
$input-btn-padding-y-lg: .5rem;
$input-btn-padding-x-lg: 1rem;

$yiq-contrasted-threshold: 150 !default;

// Customize the light and dark text colors for use in our YIQ color contrast function.
$yiq-text-dark: $gray-900 !default;
$yiq-text-light: $white !default;
@function color-yiq($color) {
  $r: red($color);
  $g: green($color);
  $b: blue($color);

  $yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000;

  @if ($yiq >= $yiq-contrasted-threshold) {
    @return $yiq-text-dark;
  } @else {
    @return $yiq-text-light;
  }
}

$btn-focus-box-shadow: 0 0 0 .25rem rgba($primary, .125);
$btn-active-box-shadow: inset 0 3px 3px 0 rgba(#000, .125);
$btn-box-shadow: inset 0 1px 0 rgba(#fff, .15), 0 1px 1px rgba(#000, .075);
.btn{
  display: inline-block;
  line-height: 1.5;
  text-align: center;
  vertical-align: middle;
  white-space: nowrap;
  padding: $input-btn-padding-y $input-btn-padding-x;
  border: 1px solid transparent;
  border-radius: .25rem;
  outline: 0;
  &.disabled, &:disabled{
    opacity: .65;
    box-shadow: none; // 干掉 focus 效果
  }
  &:not(.disabled):not(:disabled){
    &.focus, &:focus{
      box-shadow: $btn-focus-box-shadow;
      outline: 0; // 把 webkit 的默认样式干掉
    }
    cursor: pointer;
    &.active,&:active{
      // 点击效果
      box-shadow: $btn-active-box-shadow;
      &.focus, &:focus{
        box-shadow: $btn-focus-box-shadow, $btn-active-box-shadow;
      }
    }
  }
} 

@each $color-name, $color-value in $theme-colors{
  .btn-#{$color-name}{
    color: color-yiq($color-value);
    background: $color-value;
    &:not(.disabled):not(:disabled){
      &:hover{
        $hover-color: darken($color-value, 10%);
        border-color: $hover-color;
        background-color: $hover-color;
        color: color-yiq($hover-color);
      }
      &.focus, &:focus{
        box-shadow: 0 0 0 .25rem rgba($color-value, .5);
      }
    }
  }
  .btn-outline-#{$color-name}{
    color: $color-value;
    background: transparent;
    border: 1px solid $color-value;
    &:not(:disabled):not(.disabled){
      &:focus, &.focus,&.hover, &:hover{
        background: $color-value;
        color: color-yiq($color-value);
      }
      &:focus, &.focus{
        box-shadow: 0 0 0 .25rem rgba($color-value, .5);
      }
    }
  }
  
}
.close{
  font-size: 1.5rem;
  font-weight: 700;
  float: right;
  opacity: .75;
  cursor: pointer;
  &:hover, &.hover{
    opacity: 1;
  }
}
button.close{
  background: transparent;
  outline: 0;
  border: 0;
}