Polishing the App

Our app has all its features working, but it looks rough. In the section on CSS fundamentals, we learned selectors, properties, and how to link a stylesheet. Now we will apply polished, professional styles.

The CSS we are about to use includes techniques like flexbox layouts and gradients. We have not covered these yet, but you will run into them as you keep learning web development. For now, we will apply the styles and briefly explain what they do.

The Complete CSS

Replace the entire contents of index.css with the following:

html {
  box-sizing: border-box;
  font-size: 16px;
  height: 100%;
  font-family: "Poppins", sans-serif;
  background-color: #282828;
  color: #e5e5e5;
}

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

body,
h1,
h2,
h3,
h4,
h5,
h6,
p,
ol,
ul {
  margin: 0;
  padding: 0;
  font-weight: normal;
}

ol,
ul {
  list-style: none;
}

img {
  max-width: 80%;
  height: auto;
  transform: rotate(-25deg);
}

button {
  margin: auto;
  border: none;
  outline: none;
  border-radius: 0.5rem;
  background: #996fe5;
  color: #e5e5e5;
  font-size: larger;
}

button:hover {
  opacity: 90%;
}

button:active {
  transform: scale(0.98);
}

#app {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  text-align: center;
  gap: 2rem;
  max-width: 412px;
  margin: 0 auto;
  min-height: 100vh;
  background: linear-gradient(#8462bd, #4c0db8);
  background-repeat: no-repeat;
  font-size: large;
}

#prompt-section {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  padding: 2rem;
}

#result-section {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  padding: 2rem;
}

.button-group {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
}

#calc-btn {
  padding: 0.5rem 2rem 0.5rem 2rem;
}

#refresh-btn {
  padding: 0.5rem 2rem 0.5rem 2rem;
}

#return-btn {
  padding: 0.5rem;
}

#img-container {
  display: flex;
  justify-content: flex-start;
  align-items: flex-end;
  overflow: hidden;
}

#wakeup-hours-div {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.cycle {
  background-color: #e5e5e5;
  color: #282828;
  padding: 0.5rem;
  border-radius: 0.5rem;
  font-size: larger;
}

#cycle-1 {
  background: #ffb9af;
}
#cycle-2 {
  background: #ffdaa3;
}
#cycle-3 {
  background: #e5e5e5;
}
#cycle-4 {
  background: #b5ffff;
}
#cycle-5 {
  background: #87fda1;
}
#cycle-6 {
  background: #b1ff8c;
}

.hidden {
  display: none !important;
}

What Is Happening in the CSS

Here is a brief overview of the key techniques used:

  • CSS Reset: The rules for *, body, headings, etc. remove default browser styling so we start from a consistent baseline.

  • Flexbox layout (display: flex): A CSS layout system that makes it easy to arrange elements in rows or columns, center content, and distribute space. The flex-direction, align-items, justify-content, and gap properties control how children are arranged.

  • Moon positioning: The #app uses justify-content: space-between, which pushes the image container to the bottom. The #img-container uses flexbox to position the moon at the bottom-left corner.

  • Gradient background (linear-gradient): Creates a smooth color transition from purple to darker purple.

  • Viewport units (100vh): The vh unit means “viewport height.” Setting min-height: 100vh ensures the app fills at least the full viewport height.

  • Transform effects (rotate, scale): CSS can rotate, scale, and move elements. We rotate the moon image and shrink buttons slightly when clicked.

  • Color-coded cycles: Each wake-up time has a unique ID (cycle-1 through cycle-6), so we can give each one a different background color. Warmer colors (red, orange) mean less sleep. Cooler colors (blue, green) mean more sleep.

A Note on !important

Notice that the .hidden class uses !important:

.hidden {
  display: none !important;
}

When two CSS rules conflict, the more specific one wins. ID selectors (#result-section) are more specific than class selectors (.hidden). So if #result-section has display: flex, it would normally override display: none from .hidden, and the hidden class would not work.

The !important flag overrides normal specificity rules. Use it sparingly. It can make CSS harder to maintain if overused. But for utility classes like .hidden that must always work, it is the right choice.

You will learn these techniques properly as you continue with CSS. For now, the important thing is that you can read the CSS and get a general sense of what each section does.

Updating the JavaScript

We want the moon image to disappear when showing the results, and reappear when going back. Add a reference to the image container at the top of index.js:

const imageContainer = document.getElementById("img-container");

Update calcWakeUpTimes to also hide the image container:

promptSection.classList.add("hidden");
imageContainer.classList.add("hidden");
resultSection.classList.remove("hidden");

And update goBack to show it again:

function goBack() {
  promptSection.classList.remove("hidden");
  imageContainer.classList.remove("hidden");
  resultSection.classList.add("hidden");
}

Testing the Complete App

Refresh and test the full flow:

  1. Click Calculate. The prompt and moon disappear, and you see 6 color-coded wake-up times.
  2. Click Refresh. The times should recalculate.
  3. Click . You should return to the initial screen with the moon.
  4. Click Calculate again. You should be back at the results.

Your app should look and behave like this:

Checkpoint: Commit your progress.

git add .
git commit -m "wakeup-06: Polish the app with final styles"
git push