- PVSM.RU - https://www.pvsm.ru -

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

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

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

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

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

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

Начнём со взаимодействия с пользователем. Как без 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.

Заключение

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

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

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

Как написать калькулятор на HTML и CSS без JavaScript - 2
Краткий каталог курсов и профессий

Автор:
honyaki

Источник [31]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/programmirovanie/374132

Ссылки в тексте:

[1] калькулятора: https://quarknerd.github.io/noJS/calc.html

[2] Fullstack-разработке на Python: https://skillfactory.ru/python-fullstack-web-developer?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_fpw_160422&utm_term=lead

[3] HAML: https://haml.info/

[4] SCSS: https://sass-lang.com/

[5] весь: https://github.com/QuarkNerd/noJS/

[6] Профессия Fullstack-разработчик на Python: https://skillfactory.ru/python-fullstack-web-developer?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_fpw_160422&utm_term=conc

[7] Профессия Frontend-разработчик: https://skillfactory.ru/frontend-razrabotchik?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_fr_160422&utm_term=conc

[8] востребованную профессию: https://skillfactory.ru/catalogue?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=sf_allcourses_160422&utm_term=conc

[9] Профессия Data Scientist: https://skillfactory.ru/data-scientist-pro?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=data-science_dspr_160422&utm_term=cat

[10] Профессия Data Analyst: https://skillfactory.ru/data-analyst-pro?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=analytics_dapr_160422&utm_term=cat

[11] Курс «Математика для Data Science»: https://skillfactory.ru/matematika-dlya-data-science#syllabus?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=data-science_mat_160422&utm_term=cat

[12] Курс «Математика и Machine Learning для Data Science»: https://skillfactory.ru/matematika-i-machine-learning-dlya-data-science?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=data-science_matml_160422&utm_term=cat

[13] Курс по Data Engineering: https://skillfactory.ru/data-engineer?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=data-science_dea_160422&utm_term=cat

[14] Курс «Machine Learning и Deep Learning»: https://skillfactory.ru/machine-learning-i-deep-learning?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=data-science_mldl_160422&utm_term=cat

[15] Курс по Machine Learning: https://skillfactory.ru/machine-learning?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=data-science_ml_160422&utm_term=cat

[16] Профессия Fullstack-разработчик на Python: https://skillfactory.ru/python-fullstack-web-developer?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_fpw_160422&utm_term=cat

[17] Курс «Python для веб-разработки»: https://skillfactory.ru/python-for-web-developers?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_pws_160422&utm_term=cat

[18] Профессия Frontend-разработчик: https://skillfactory.ru/frontend-razrabotchik?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_fr_160422&utm_term=cat

[19] Профессия Веб-разработчик: https://skillfactory.ru/webdev?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_webdev_160422&utm_term=cat

[20] Профессия iOS-разработчик: https://skillfactory.ru/ios-razrabotchik-s-nulya?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_ios_160422&utm_term=cat

[21] Профессия Android-разработчик: https://skillfactory.ru/android-razrabotchik?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_andr_160422&utm_term=cat

[22] Профессия Java-разработчик: https://skillfactory.ru/java-razrabotchik?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_java_160422&utm_term=cat

[23] Профессия QA-инженер на JAVA: https://skillfactory.ru/java-qa-engineer-testirovshik-po?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_qaja_160422&utm_term=cat

[24] Профессия C#-разработчик: https://skillfactory.ru/c-sharp-razrabotchik?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_cdev_160422&utm_term=cat

[25] Профессия Разработчик игр на Unity: https://skillfactory.ru/game-razrabotchik-na-unity-i-c-sharp?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_gamedev_160422&utm_term=cat

[26] Курс «Алгоритмы и структуры данных»: https://skillfactory.ru/algoritmy-i-struktury-dannyh?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_algo_160422&utm_term=cat

[27] Профессия C++ разработчик: https://skillfactory.ru/c-plus-plus-razrabotchik?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_cplus_160422&utm_term=cat

[28] Профессия Этичный хакер: https://skillfactory.ru/cyber-security-etichnij-haker?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_hacker_160422&utm_term=cat

[29] Курс по DevOps: https://skillfactory.ru/devops-ingineer?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=coding_devops_160422&utm_term=cat

[30] Все курсы: https://skillfactory.ru/catalogue?utm_source=habr&utm_medium=habr&utm_campaign=article&utm_content=sf_allcourses_160422&utm_term=cat

[31] Источник: https://habr.com/ru/post/661343/?utm_source=habrahabr&utm_medium=rss&utm_campaign=661343