<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>スマホ電卓Pro</title>
<style>
/* 基本設定 */
* {
box-sizing: border-box;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
}
body {
margin: 0;
padding: 0;
height: 100dvh; /* アドレスバー対策 */
width: 100vw;
display: flex;
flex-direction: column;
background-color: #000;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
overflow: hidden;
}
/* 計算結果画面 */
#display-container {
/* 画面の25%を使用(以前より少し狭くしてボタンに譲る) */
flex: 0 0 25%;
display: flex;
flex-direction: column; /* 単位と数字を縦に並べる */
justify-content: flex-end;
align-items: flex-end;
padding: 20px;
padding-top: 50px;
position: relative;
}
/* 単位を表示する小さな文字 */
#unit-label {
color: #a5a5a5;
font-size: 1.2rem;
margin-bottom: 5px;
opacity: 0; /* 最初は隠しておく */
transition: opacity 0.3s;
}
#display {
width: 100%;
background: transparent;
border: none;
color: white;
font-size: 4rem; /* 数字の大きさ */
text-align: right;
outline: none;
font-weight: 300;
padding: 0;
margin: 0;
}
/* ボタンエリア */
.buttons {
/* 画面の残り(75%)を使ってボタンを縦長にする */
flex: 1;
padding-bottom: calc(40px + env(safe-area-inset-bottom));
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(5, 1fr); /* 均等に縦長になる */
gap: 12px;
padding-left: 15px;
padding-right: 15px;
}
button {
border: none;
font-size: 2rem;
border-radius: 1000px; /* どんなに縦長でもきれいな丸み(カプセル型)にする */
cursor: pointer;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
transition: all 0.1s;
/* 縦長ボタンのためにアスペクト比制限を外してgrid-rowに従わせる */
height: 100%;
}
button:active {
filter: brightness(0.8); /* 押したときに暗くする */
transform: scale(0.98); /* 少し縮む */
}
/* 数字ボタン */
.number {
background-color: #333333;
}
/* 演算子ボタン(右側) */
.operator {
background-color: #ff9f0a;
font-size: 2.5rem; /* 記号を少し大きく */
}
/* 機能ボタン(上段) */
.func {
background-color: #a5a5a5;
color: black;
font-weight: 500;
}
/* 0ボタン */
.zero-btn {
grid-column: span 2;
justify-content: flex-start;
padding-left: 35px;
}
/* 時間ボタン */
.time-btn {
background-color: #a5a5a5;
color: black;
font-size: 1.1rem;
font-weight: bold;
line-height: 1.2;
flex-direction: column; /* 文字を2行にできるように */
}
</style>
</head>
<body>
<div id="display-container">
<div id="unit-label">秒</div>
<input type="text" id="display" readonly value="0">
</div>
<div class="buttons">
<button class="func" onclick="clearDisplay()">C</button>
<button class="func" onclick="deleteLast()">←</button>
<button class="time-btn" id="btn-time" onclick="cycleTime()">
時間<br><span style="font-size:0.7em">変換</span>
</button>
<button class="operator" onclick="appendDisplay('/')">÷</button>
<button class="number" onclick="appendDisplay('7')">7</button>
<button class="number" onclick="appendDisplay('8')">8</button>
<button class="number" onclick="appendDisplay('9')">9</button>
<button class="operator" onclick="appendDisplay('*')">×</button>
<button class="number" onclick="appendDisplay('4')">4</button>
<button class="number" onclick="appendDisplay('5')">5</button>
<button class="number" onclick="appendDisplay('6')">6</button>
<button class="operator" onclick="appendDisplay('-')">−</button>
<button class="number" onclick="appendDisplay('1')">1</button>
<button class="number" onclick="appendDisplay('2')">2</button>
<button class="number" onclick="appendDisplay('3')">3</button>
<button class="operator" onclick="appendDisplay('+')">+</button>
<button class="number zero-btn" onclick="appendDisplay('0')">0</button>
<button class="number" onclick="appendDisplay('.')">.</button>
<button class="operator" onclick="calculateResult()">=</button>
</div>
<script>
const display = document.getElementById('display');
const unitLabel = document.getElementById('unit-label');
const btnTime = document.getElementById('btn-time');
const operators = ['/', '*', '-', '+'];
// 時間変換の状態管理 (0:なし, 1:秒, 2:分, 3:時, 4:日, 5:年)
let timeState = 0;
const unitNames = ["", "秒", "分", "時間", "日", "年"];
function appendDisplay(input) {
// 新しい数字を入れたら、単位変換モードをリセットする
resetTimeMode();
const currentVal = display.value;
const lastChar = currentVal.slice(-1);
if (currentVal === '0' && !operators.includes(input) && input !== '.') {
display.value = input;
return;
}
if (operators.includes(input) && operators.includes(lastChar)) {
return;
}
display.value += input;
}
function clearDisplay() {
display.value = "0";
resetTimeMode();
}
function deleteLast() {
resetTimeMode();
if (display.value.length > 1) {
display.value = display.value.slice(0, -1);
} else {
display.value = "0";
}
}
// 時間変換機能
function cycleTime() {
try {
// まず現在の数値を確定させる(計算途中なら計算する)
let val = parseFloat(eval(display.value));
// 次のモードへ
timeState++;
// 年(5)の次は秒(1)に戻る
if (timeState > 5) {
timeState = 1;
}
// 単位変換のロジック
// 1回目(State 1): 入力値を「秒」として扱う(値は変えない)
// 2回目(State 2): 秒 → 分 (/60)
// 3回目(State 3): 分 → 時 (/60)
// 4回目(State 4): 時 → 日 (/24)
// 5回目(State 5): 日 → 年 (/365)
// ループ時(State 1): 年 → 秒 (*365*24*60*60)
if (timeState === 1) {
// 年から秒へ戻る場合のみ計算が必要(それ以外の初回クリックは何もしない)
if (unitLabel.innerText === "年") {
val = val * 365 * 24 * 60 * 60;
}
// 初回クリック時は「入力された数字=秒」とみなすので値はいじらない
} else if (timeState === 2) {
val = val / 60; // 秒→分
} else if (timeState === 3) {
val = val / 60; // 分→時
} else if (timeState === 4) {
val = val / 24; // 時→日
} else if (timeState === 5) {
val = val / 365; // 日→年
}
// 計算結果を表示(小数点以下が多くなりすぎないように調整可。今回はそのまま)
display.value = val;
// 画面右上に単位を表示
unitLabel.style.opacity = 1;
unitLabel.innerText = unitNames[timeState];
// ボタンの文字を次の単位案内に変える(オプション)
// btnTime.innerHTML = unitNames[timeState];
} catch (e) {
display.value = "Error";
}
}
// 数字や記号を押したら単位モードを解除する関数
function resetTimeMode() {
timeState = 0;
unitLabel.style.opacity = 0;
unitLabel.innerText = "";
}
function calculateResult() {
try {
let expression = display.value;
display.value = new Function('return ' + expression)();
// 計算したら単位モードはリセット
resetTimeMode();
} catch (error) {
display.value = "Error";
}
}
</script>
</body>
</html>
使用変数
| appendDisplay -------( Function ) | |
| btnTime | |
| calculateResult -------( Function ) | |
| charset | |
| class | |
| clearDisplay -------( Function ) | |
| content | |
| currentVal | |
| cycleTime -------( Function ) | |
| deleteLast -------( Function ) | |
| display | |
| expression | |
| fit | |
| id | |
| innerHTML | |
| innerText | |
| lang | |
| lastChar | |
| name | |
| onclick | |
| opacity | |
| operators | |
| resetTimeMode -------( Function ) | |
| scalable | |
| scale | |
| style | |
| timeState | |
| type | |
| unitLabel | |
| unitNames | |
| val | |
| value | |
| width |