首页 > 解决方案 > CSS 中 ::after 和 ::before 的区别

问题描述

我正在关注这个关于构建 javascript 计算器的教程,以了解更多关于 Web 开发的信息。下面的 CSS 代码在按下运算符(+、-、*、/)键时添加样式。当按下操作员键时,它应该变暗,直到按下另一个键以显示操作员处于“活动状态”。但是,当一次又一次地按下相同的操作键时,仍然应该有一些重复点击的视觉指示。

const calculator = document.querySelector(".calculator");
const keys = calculator.querySelector(".calculator__keys");
const display = document.querySelector(".calculator__display");

keys.addEventListener('click', e => {
  if (e.target.matches('button')) {
    const key = e.target;
    const action = key.dataset.action;
    const keyValue = key.textContent;
    const displayNum = display.textContent;

    Array.from(key.parentNode.children).forEach(k=>k.classList.remove('is-depressed'));

    if (!action) {
      if (displayNum === "0" || calculator.dataset.previousKeyType === "operator") {
        display.textContent = keyValue;
        calculator.dataset.previousKeyType = null;
      } else {
        display.textContent = displayNum + keyValue;
      }
      calculator.dataset.previousKeyType = "number";
      console.log("Number key")
    }
    if (action === "decimal") {
      if (calculator.dataset.previousKeyType === "operator") {
        display.textContent = "0.";
        calculator.dataset.previousKeyType = "decimal";
      } else if (!displayNum.includes(".")) {
        display.textContent += ".";
      }
    }
    if (
      action === 'add' ||
      action === 'subtract' ||
      action === 'multiply' ||
      action === 'divide'
    ) {
      calculator.dataset.previousKeyType = "operator";
      calculator.dataset.previousNum = displayNum;
      calculator.dataset.operator = action;
      key.classList.add("is-depressed");
    }
    if (action === "clear") {
      calculator.dataset.previousKeyType = "clear";
      console.log("AC key");
    }

    if (action === "calculate") {
      calculator.dataset.previousKeyType = "calculate";
      const secondVal = displayNum;
      const firstVal = calculator.dataset.previousNum;
      const operator = calculator.dataset.operator;
      display.textContent = calculate(firstVal, secondVal, operator);

    }
  }
});

function calculate(firstVal, secondVal, operator) {
  let num1 = +firstVal;
  let num2 = +secondVal;
  if (operator === "add") {
    return num1 + num2;
  } else if (operator === "subtract") {
    return num1 - num2;
  } else if (operator === "multiply") {
    return num1 * num2;
  } else {
    return num1 / num2;
  }
}
// NOTE: You don't need to mess around with
// CSS to follow the tutorial. Focus on the
// JavaScript instead!
// =========================

// Some personal resets
html {
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

body {
  margin: 0;
}

/* Responsive Images */

embed,
iframe,
img,
object,
video {
  max-width: 100%;
}

h1,
h2,
h3,
h4,
h5,
h6,
ul,
ol,
li,
p,
pre,
blockquote,
figure,
hr {
  margin: 0;
  padding-right: 0;
  padding-left: 0;
}

a {
  text-decoration: none;
}

a:focus {
  outline: none;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  display: block;
}

/* Removes all decimals and discs from lists */

ol,
ul {
  list-style: none;
}

/*
 * Completely resets form items
 * ----------------------------
 * Super hard reset that removes all borders
 * and radiuses of all form items (including
 * checkboxes and radios)
 */

input,
textarea,
button {
  border: 0;
  border-radius: 0;
  background-color: transparent;
  font-size: inherit;
  font-family: inherit;
  font-weight: inherit;
  outline: none;
  appearance: none;
  text-align: left;
}

input:hover,
input:active,
input:focus,
textarea:hover,
textarea:active,
textarea:focus,
button:hover,
button:active,
button:focus {
  outline: none;
}

:root {
  font-family: Helvetica, Arial, sans-serif;
}

html {
  font-size: 175%;
  font-weight: 300;
  line-height: 1.3;
}

body {
  align-items: center;
  background-image: linear-gradient(236deg, #74ebd5, #acb6e5);
  display: flex;
  height: 100vh;
  justify-content: center;
}

.container {
  max-width: 20em;
}

.container > p {
  text-align: center;
}

.calculator {
  border-radius: 12px;
  box-shadow: 0 0 40px 0px rgba(0, 0, 0, 0.15);
  margin-left: auto;
  margin-right: auto;
  margin-top: 2em;
  max-width: 15em;
  overflow: hidden;
}

.calculator__display {
  background-color: #222222;
  color: #fff;
  font-size: 1.714285714em;
  padding: 0.5em 0.75em;
  text-align: right;
}

.calculator__keys {
  background-color: #999;
  display: grid;
  grid-gap: 1px;
  grid-template-columns: repeat(4, 1fr);
}

.calculator__keys > * {
  background-color: #fff;
  padding: 0.5em 1.25em;
  position: relative;
  text-align: center;
}

.calculator__keys > *:active::after,
.calculator__keys > .is-depressed::before {
  background-color: rgba(0, 0, 0, 0.2);
  bottom: 0;
  box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5) inset;
  content: "";
  left: 0;
  opacity: 0.3;
  position: absolute;
  right: 0;
  top: 0;
  z-index: 1;
}

.key--operator {
  background-color: #eee;
}

.key--equal {
  background-image: linear-gradient(to bottom, #fe886a, #ff7033);
  grid-column: -2;
  grid-row: 2 / span 4;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Calculator</title>
    <link rel="stylesheet" href="calculator.css" type="text/css">
    <script type="text/javascript" src="calculator.js" defer></script>
  </head>
  <body>
    <div class="container">
        <p>
          This component works exactly like the calculator you know. Click any number to start calculating!
        </p>
        <div class="calculator">
          <div class="calculator__display">0</div>

          <div class="calculator__keys">
            <button class="key--operator" data-action="add">+</button>
            <button class="key--operator" data-action="subtract">-</button>
            <button class="key--operator" data-action="multiply">&times;</button>
            <button class="key--operator" data-action="divide">÷</button>
            <button>7</button>
            <button>8</button>
            <button>9</button>
            <button>4</button>
            <button>5</button>
            <button>6</button>
            <button>1</button>
            <button>2</button>
            <button>3</button>
            <button>0</button>
            <button data-action="decimal">.</button>
            <button data-action="clear">AC</button>
            <button class="key--equal" data-action="calculate">=</button>
          </div>
        </div>
      </div>
  </body>
</html>

该类is-depressed是我在单击它时添加到操作符键元素的类。上面的代码没有给出多次点击的视觉指示,但是当我更改*:active::before为时*:active::after,代码会执行我想要的操作。这是为什么?

.calculator__keys > *:active::after,
.calculator__keys > .is-depressed::before {
  background-color: rgba(0, 0, 0, 0.2);
  bottom: 0;
  box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5) inset;
  content: "";
  left: 0;
  opacity: 0.3;
  position: absolute;
  right: 0;
  top: 0;
  z-index: 1;
}

标签: javascripthtmlcss

解决方案


答案很简单。拥有:active::after.is-depressed::before意味着当你的元素被按下时,你会改变before元素,当你再次点击时,你会改变after元素,所以两个不同的元素。

当同时拥有它们时,before它是一个元素,并且已经通过更新,.is-depressed因此活动状态将什么也不做。

用一个更简单的例子来说明这一点:

.box {
  border:1px solid;
  width:150px;
  height:150px;
  display:inline-block;
  position:relative;
}

.box:hover::before,
.box.active::before{
   content:"";
   display:block;
   height:50%;
   background:red;
}
<div class="box"></div>

<div class="box active"></div>

在上面,当您将鼠标悬停在第二个元素上时,什么都不会发生,因为active已经完成了这项工作:

.box {
  border:1px solid;
  width:150px;
  height:150px;
  display:inline-block;
  position:relative;
}

.box:hover::after,
.box.active::before{
   content:"";
   display:block;
   height:50%;
   background:red;
}
<div class="box"></div>

<div class="box active"></div>

在最后一个示例中,活动将添加前元素,悬停将添加后元素。就如此容易。


推荐阅读