Lab 5 - CSS: Layout

Due: .

Layout

In this lab, you will use CSS and JavaScript to make a reactive page that changes layout dynamically. You will use a combination of fixed and flex-box display properties, then use buttons to change what classes are controlling the layout.

All code must validate cleanly (no errors or warnings) through the standard validation tools listed below. You must resolve all errors and warnings before submission. For individual CSS properties, please refer to the MDN reference list.

Starting Code

Start by extracting provided source code and opening the files in your preferred text editor:

For this lab, you will need to modify all three files and submit them to Gradescope.

Semantic structure and fixed navbar

  1. Start with the index.html file. Create a nav element containing an unordered list. Each item will contain a button with an id attributed as specified in the file. No classes or other attributes should be added to any of these elements, as all presentation and dynamic features will be added using CSS and JavaScript.
  2. Inside the main, add 2 randomly selected SQUARE img elements (200x200). Use picsum.photos to get the URLs for these images. Make sure to add alt text.
    • At this point, you should see a list with three bullet points with some ugly buttons next to them. Below that you should see two random images with a little bit of spacing around them.
    • Add a link element to the head to reference styles.css and reload the page. What changed?
  3. In the styles.css file, start by getting the header and main into position. To do this, specify the appropriate properties to the header and main rules (including display and position) according to the comments. Set the color variables in the :root rule and give the header a background so you can see it.
  4. Wow, those buttons look bad! Let’s fix them.
    • Use descendant selectors to update the nav list and list items. Get rid of the bullet points, add a right margin, and switch the list items to be in a row rather than a column (i.e., switch them from block to inline).
    • They’re still kind of ugly. Use a descendant selector to update the button style properties. Add some padding and increase the font size. Give them no border but use border-radius to curve the corners. Use those spiffy color variables you defined up in :root.
    • OK, now we’re making progress.

Dynamic buttons

  1. Buttons look and feel so much better when they appear to react when we move the mouse over them or click on them. Let’s take care of that.
    • Add a new rule for the button when it is in the :hover state. When this happens, give the button an outline that is at least 3px in size and matches the text color of the button.
    • We won’t be able to use it yet, but add another rule based on the button also having a class called active. In this class, switch the text and background colors of the button.
    • That’s starting to look nice. In this image, the “Spread Out” button has the active class while the mouse is hovering over “Rotate Direction”.
  2. The :hover pseudoclass is automatically built into the web browser, but we need to do some work for the active class. It’s JavaScript time!
    • Add a script element to index.html to reference flex.js then open this file.
    • The default implementation shows a pop-up box when you click the “Spread Out” button. Get rid of that and replace it with code that adds or removes the active class we created a bit ago. To do this, we’re going to manipulate the spreadButton.classList. Rather than keeping all the classes in a string (which you would do in HTML), the DOM maintains them as a list.
    • If you write more than one line of code here, you’re doing it wrong. Yes, you can add some logic this:
      if (spreadButton.classList.contains('active') {
        // Button has class="active" so remove it
        spreadButton.classList.remove('active');
      } else {
        // Button doesn't have the class so add it
        spreadButton.classList.add('active');
      }
      
      But really? Why? Just use toggle, which does that work for you.
    • If you click on the “Spread Out” button, it should turn dark. Click it again and it goes back to the original coloring. If it works, add some more code to do the same thing for the “Rotate Direction” button. You’ll need to add a new variable at the top of the file, then add code similar to what was provided for the spreadButton toward the bottom of the file.

Flex

  1. Toggling button colors is cool, but it’d be even better if the buttons…actually did something? Let’s start with spreading things out.
    • Head back to styles.css. Create a new rule that only applies to the main element when it has the “spread” class. This rule will use the space-around value to add spacing to elements along the main axis.
    • Give it a try to make sure you’ve got the flex-box set up properly. If you load page, the images should be centered vertically and pushed all the way to the left edge of the window. But if you add the class="spread" to the main element in the HTML and reload the page, they should be spaced out horizontally. Good? Good. Now, remove class="spread" from your HTML. We’re controlling that in other ways.
    • Back to flex.js. We need to add a new mainElement global variable and use document.querySelector to grab the main. (Note that we are NOT adding an event listener to main, so don’t copy that line of code.)
    • Just like the buttons have a classList, main does, too. Add another line of code to your spacing function so that it toggles the “spread” class.
    • Click the “Spread Out” button a few times. The images should switch back and forth from the default positioning on the left to spaced out horizontally. And the button should still be inverting colors each time.
  2. Now let’s add some rotation.
    • Add some more CSS to switch the flex-box to a column when the “vert” class is present for the main element. Just like spreading things out, add some JavaScript code to toggle this class.
    • Notice what happens if you click both buttons to activate both classes. Can you explain why? Does it matter which class you turn on/off first?

DOM manipulation

  1. We’ve still got one more button hanging around, so let’s do something with it.
    • Add a new global variable and the associated initialization code at the bottom of the flex.js file to reference the button.
    • In addImg, use document.createElement to create a new img element. Set the src and alt attributes to grab another random square image. HINT: HTML attributes just become object fields in the DOM; so imgElement.src can be used to view or change the <img src="..."> field.
    • Reload the page and click the “Add Image” button. Nothing happens. Huh. Oh, that’s right, we created the img element, but we didn’t tell the browser where we wanted the image to be added. Use appendChild to add it as a new child of the main element.

Going further

  1. The original index.html file may have looked a bit odd. It was missing closing tags for head, body, and html. It turns out, that’s perfectly fine and valid. The HTML5 spec indicates that certain tags, including closing tags, are optional.
  2. If you add enough images and make the flex-box into a column, notice that the header bar covers up the images. What CSS rule could you add to fix this?
  3. What if we don’t like one of the random images? Let’s find a way to delete it. In the initialization code, use document.querySelectorAll to get all of the images. This function returns an array, so you can do images.forEach to loop through them. Use this to add an event listener to call removeImg for each one. In this function, call remove on the passed parameter. This won’t work. Use the console to print out the element that gets passed and try to figure out the problem. You can then read the textbook chapter on events to try to fix it.