Как написать калькулятор на HTML и CSS без JavaScript

от автора

Материалом о разработке калькулятора на CSS и HTML, без файла JS, тега script и обработчиков событий в HTML делимся к старту курса по Fullstack-разработке на Python. За подробностями приглашаем под кат.

Постановка задачи

В проектах CSS часто в обычные статические HTML и CSS компилируются HAML и SCSS. Последние при этом применяются во многих сумасшедших проектах, но свой я решил не усложнять: взгляните на весь код.

Как это сделать?

Начнём со взаимодействия с пользователем. Как без JS понять, что кнопка нажата? Ответ: при помощи значений радиокнопок:

<input type="radio" name="x" id="q-1" />  <input type="radio" name="x" id="q-2" />  <label for="q-1">Quote 1</label> <label for="q-2">Quote 2</label>  <p class="quote-1">...</p> <p class="quote-2">...</p>

и

input, p { display: none }  #q-1:checked ~ .quote-1 { display: block; } #q-2:checked ~ .quote-2 { display: block; }

дают результат:

Метки (label) соединены с input так, что нажатие на них станет нажатием на input. Метки упрощают стиль, поэтому они лучше нажатия на радиокнопку напрямую.

Символ ~ — это селектор, выбирающий элементы на том же уровне сложности: A ~ B соответствует элементам B после A. Код выше по умолчанию скрывает элементы p, отображая их, только когда подключенная радиокнопка выбрана.

Переменные и счётчики CSS

Значения счётчиков в функции calc неприменимы, поэтому, чтобы сгенерировать число, объявим переменную. Напишем имя свойства с двумя дефисами (—) в начале и любым значением CSS: —colour: brown или —digit: 3. Для подстановки переменной вызовите функцию CSS var.

Счётчики CSS хранят и отображают числа. Они применяются, например, для автоматической нумерации разделов.

<input type="radio" name="theFirstDigit" id="set-to-1" />  <input type="radio" name="theFirstDigit" id="set-to-2" />  <input type="radio" name="theFirstDigit" id="set-to-3" />  <!-- insert labels -->  <div class="number-dsplay"></div>

и

#set-to-1:checked ~ div { --digit: 1; } #set-to-2:checked ~ div { --digit: 2; } #set-to-3:checked ~ div { --digit: 3; }  .number-display { counter-increment: digit var(--digit);  } .number-display::after { content: counter(digit) }

дают результат:

Когда пользователь отмечает кнопку, внутри div задаётся значение переменной —digit, наследуемое всеми дочерними элементами. Это значение нельзя вывести напрямую, поэтому увеличим счётчик digit и отобразим его через сгенерированный content.

Чтобы получить числа больше 9, нужно просто продублировать уже существующие цифры. За счёт тщательно продуманной структуры HTML и использования промежуточных переменных дублирование CSS сводится к минимуму:

!-- digit inputs name="theFirstDigit -->  <div class="first-digit">   <!-- digit inputs name="theSecondDigit" -->    <div class="second-digit">     <!-- ..and so on -->        </div> </div>
/* Include previous CSS */  .first-digit { --first-digit: var(--digit); } .second-digit { --second-digit: var(--digit); }

Переменная —digit по-прежнему задаётся через input, каждый отдельный div принимает это значение и присваивает его —first-digit, —second-digit и так далее: повторять код #set-to-1:checked для каждой цифры не нужно.

Функция CSS calc

Функция calc в CSS выполняет вычисления и применяется, например когда задаётся значение width (ширины): calc(100% — 95px). Определим с помощью calc число элемента input, а также результат всех вычислений:

[name="theFirstDigit"]:checked ~ * .set-number { --number: var(--first-digit); } [name="theSecondDigit"]:checked ~ * .set-number {     --number: calc(var(--first-digit)*10 + var(--second-digit));  } [name="theThirdDigit"]:checked ~ * .set-number {     --number: calc(var(--first-digit)*100 + var(--second-digit)*10 + var(--third-digit));  } /* and so on */

Селектор * выбирает все элементы, поэтому в коде выше вы найдёте .set-number — потомка любого элемента после input с флажком и определённым именем. Второй селектор переопределяет первый просто потому, что расположен после первого.

Добавив несколько input для выбора операции, аналогичным методом мы получим окончательный ответ. В этом случае значения просто захватываются в счётчике и отображаются. Свойство content тоже может принимать строку, отображая операцию калькулятора.

@property и @counter-style

Теперь можно создать калькулятор. Но вот загвоздка: в счётчиках есть только целые числа, знаков после запятой у нас нет, поэтому нужно разделить число на целую и дробную части и найти способ округления чисел. 

Счётчики при этом использовать нельзя, ведь их нельзя завести в calc. Воспользуемся экспериментальной функцией @property: она определяет переменную с помощью такого функционала, как проверка типа или контроль за наследованием значений. Определим @property:

@property --integer {     syntax: '<integer>';     initial-value: 0;     inherits: true; }

Так любое присваиваемое —integer значение округляется до целого числа. Чтобы отобразить число с точностью до семи знаков после запятой, сначала выполним следующие вычисления. Здесь —number определяется внешним кодом:

.number-display {     --abs-number: max(var(--number), -1 * var(--number));      /* By suptracting 0.5 we make sure that we round down */     --integer: calc(var(--abs-number) - 0.5);     --decimal: calc((var(--integer) - var(--abs-number)) * 10000000);      --sign-number: calc(var( --abs-number) / var(--number)); }

Используя —integer для целых чисел и —decimal для знаков после запятой, можно увеличивать счётчики с похожими именами, но отображать их напрямую нельзя: например, для числа 1,005 значение —integer равно 1, а значение —decimal — 5. 

Знаки после запятой дополняются пользовательским свойством @counter-style, оно применяется для отображения знака «минус»: мы не можем сообщить системе, что число -0,5 — это «отрицательный нуль». Вот как правильно отобразить -0,5:

@counter-style pad-7 {     system: numeric;     symbols: "0" "1" "2" "3" "4" "5" "6" "7" "8" "9";     pad: 7 "0" }  @counter-style sign {     system: numeric;     symbols: "" ""; }  .number-display::after {     content: counter(sign-number, sign) counter(integer) "." counter(decimal, pad-7); }

Второй аргумент функции counter — это стиль. В стиле pad-7 определяется обычная система счисления, за исключением того, что любое значение с менее чем семью цифрами дополняется нулями. 

В стиле sign тоже используется числовая система, но мы определили символы пустыми, поэтому отображается в нём только знак «минус», если нужно.

Возможности

Всё это — ключевые элементы калькулятора, но осталось ещё кое-что — это стилизация. Вы могли заметить, что для каждой цифры числа в текущей конфигурации есть отдельный набор из нескольких input. 

Чтобы всегда показывать метку следующей цифры, можно применять селектор ~, :checked и свойство display, а content — разбить на отдельные элементы, таким образом показывая десятичную часть только при необходимости.

Теоретически через генерацию HTML можно приблизиться к научному калькулятору. Например, можно воспользоваться симметрией и периодичностью тригонометрических функций, применив приближённые вычисления. 

Самое сложное — скобки, ведь неизвестно, как динамически добавить их в  calc, поэтому для каждого сценария пришлось бы иметь отдельные селекторы и CSS.

Заключение

Я написал этот калькулятор просто ради забавы, но многому научился, это было очень весело, поэтому если у вас есть идея пустякового проекта, реализуйте её. Почему нет?

А пока вы практикуетесь, мы поможем прокачать ваши навыки или с самого начала освоить профессию, востребованную в любое время:

Выбрать другую востребованную профессию.

Краткий каталог курсов и профессий


ссылка на оригинал статьи https://habr.com/ru/company/skillfactory/blog/661343/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *