<div id="app">

	<span>
		<!-- Empty span here to make the grid line up properly --></span>

	<div class="card">
		<div class="flex-group">
			<input v-model="ml" type="number" id="ml">
			<label for="ml">
				ml
			</label>
		</div>
	</div>

	<span> = </span>

	<div class="card">
		<div class="flex-group">
			<input v-model="tsp" type="number" id="tsp">
			<label for="tsp">
				tsp
			</label>
		</div>
	</div>

	<span> = </span>

	<div class="card">
		<div class="flex-group">
			<input v-model="tbsp" type="number" id="tbsp">
			<label for="tbsp">
				tbsp
			</label>
		</div>
	</div>

	<span> = </span>

	<div class="card">
		<div class="flex-group">
			<input v-model="ounce" type="number" id="oz">
			<label for="oz">
				oz
			</label>
		</div>
	</div>

	<span> = </span>

	<div class="card">
		<div class="flex-group">
			<input v-model="cup" type="number" id="cup">
			<label for="cup">
				cup{{ cup != 1 ? 's' : '' }}
			</label>
		</div>
	</div>

	<span> = </span>

	<div class="card">
		<div class="flex-group">
			<input v-model="pint" type="number" id="pint">
			<label for="pint">
				pint{{ pint != 1 ? 's' : '' }}

			</label>
		</div>
	</div>

	<span> = </span>

	<div class="card">
		<div class="flex-group">
			<input v-model="quart" type="number" id="quart">
			<label for="quart">
				quart{{ quart != 1 ? 's' : '' }}
			</label>
		</div>
	</div>

	<span> = </span>

	<div class="card">
		<div class="flex-group">
			<input v-model="liter" type="number" id="liter">
			<label for="liter">
				liter{{ liter != 1 ? 's' : '' }}
			</label>
		</div>
	</div>

	<span> = </span>

	<div class="card">
		<div class="flex-group">
			<input v-model="gallon" type="number" id="gallon">
			<label for="gallon">
				gallon{{ gallon != 1 ? 's' : '' }}
			</label>
		</div>
	</div>
@import url("https://fonts.googleapis.com/css?family=Barlow+Condensed:300&display=swap");
@import url("https://fonts.googleapis.com/css?family=Martel&display=swap");
// Wanted to use a font with oldstyle figures for numbers. Most Google fonts don't have that option, but Martel has it built-in as its default.

$orange: #ff6a13;
$yellow: #ffd100;
$lightGray: #a7a8aa;
$darkGray: #53565a;
$lightBlue: #7ba7bc;

*,
*:before,
*:after {
	box-sizing: border-box;
	font-family: inherit;
	color: inherit;
	max-width: 100%;
}

*:focus {
	outline: none;
	background-color: $yellow;
}

*::selection {
	background: $yellow;
}

html {
	font-size: 1.125em;
}

body {
	margin: 0;
	font-family: "Barlow Condensed";
	background: #eee;
	color: $darkGray;
	min-height: 100vh;
	display: grid;
	place-content: center;
}

#app {
	display: grid;
	margin: auto;
	max-width: 24rem;
	grid-template-columns: 0.8rem minmax(12rem, 20rem);
	grid-gap: 1rem;
	padding: 1rem;

	@media (min-width: 800px) {
		transform: skewX(29deg);

		span,
		.card {
			transform: skewX(-29deg);
		}
	}

	span {
		text-align: center;
		font-size: 1.25rem;
		display: flex;
		align-items: center;
		color: $lightGray;
		margin-bottom: 0.3em;
		left: 0;
	}

	.card {
		display: grid;
		border-radius: 0.25rem;
		align-items: center;

		h2 {
			font-size: 2rem;
			font-weight: bold;
			text-align: center;
			margin: 0 0 1em;
		}

		.flex-group {
			display: grid;
			align-items: baseline;
			justify-content: space-between;
			grid-template-columns: 1fr max-content;
			grid-template-rows: 1fr;
			border-bottom: 1px solid;

			label {
				text-align: right;
				font-size: 1.25rem;
				position: relative;
			}

			input {
				font-family: "Martel";
				border: none;
				text-align: left;
				display: inline-block;
				font-size: 1.25rem;
				background: transparent;
				width: 60vw;
				box-shadow: none;

				@media (min-width: 440px) {
					width: auto;
				}

				&:focus + label {
					color: $yellow;
				}
			}
		}
	}
}
View Compiled
const app = new Vue({
	el: "#app",
	data: () => ({
		//Ounces are the only true data value here; every other value is a dependent computed property that multiplies or divides ounces
		oz: 32
	}),

	methods: {
		//Does some nice formatting on the number, if it's a decimal, to make it a little more readable and limit it to 10 total characters
		format(num) {
			num = Number(num);
			return parseInt(num) === num ? num : num.toString().substring(0, 10);
		}
	},

	computed: {
		tsp: {
			get() {
				return this.format(this.oz * 6);
			},
			set(val) {
				this.oz = val / 6;
			}
		},
		ml: {
			get() {
				return parseInt(this.format(this.oz * 29.57352968750042));
			},
			set(val) {
				this.oz = val / 29.57352968750042;
			}
		},
		tbsp: {
			get() {
				return this.format(this.oz * 2);
			},
			set(val) {
				this.oz = val / 2;
			}
		},
		ounce: {
			get() {
				return this.format(this.oz);
			},
			set(val) {
				this.oz = val;
			}
		},
		cup: {
			get() {
				return this.format(this.oz / 8);
			},
			set(val) {
				this.oz = val * 8;
			}
		},
		pint: {
			get() {
				return this.format(this.oz / 16);
			},
			set(val) {
				this.oz = val * 16;
			}
		},
		quart: {
			get() {
				return this.format(this.oz / 32);
			},
			set(val) {
				this.oz = val * 32;
			}
		},
		liter: {
			get() {
				return Number(this.format(this.oz * 0.02957352968750042)).toFixed(2);
			},
			set(val) {
				this.oz = val / 0.02957352968750042;
			}
		},
		gallon: {
			get() {
				return this.format(this.oz / 128);
			},
			set(val) {
				this.oz = val * 128;
			}
		}
	}
});
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js