Deprecated: Creation of dynamic property wpdb::$categories is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 668

Deprecated: Creation of dynamic property wpdb::$post2cat is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 668

Deprecated: Creation of dynamic property wpdb::$link2cat is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 668

Deprecated: Return type of WP_Theme::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 554

Deprecated: Return type of WP_Theme::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 595

Deprecated: Return type of WP_Theme::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 535

Deprecated: Return type of WP_Theme::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 544

Deprecated: Return type of WP_REST_Request::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 960

Deprecated: Return type of WP_REST_Request::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 980

Deprecated: Return type of WP_REST_Request::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 992

Deprecated: Return type of WP_REST_Request::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 1003

Deprecated: Return type of WP_Block_List::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 151

Deprecated: Return type of WP_Block_List::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 175

Deprecated: Return type of WP_Block_List::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 164

Deprecated: Return type of WP_Block_List::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 186

Deprecated: Return type of WP_Block_List::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 138

Deprecated: Return type of WP_Block_List::offsetExists($index) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 75

Deprecated: Return type of WP_Block_List::offsetGet($index) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 89

Deprecated: Return type of WP_Block_List::offsetSet($index, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 110

Deprecated: Return type of WP_Block_List::offsetUnset($index) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 127

Deprecated: Return type of WP_Block_List::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 199

Deprecated: Creation of dynamic property Automattic\Jetpack\Connection\Manager::$error_handler is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/src/class-manager.php on line 91

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Instagram_Gallery::$is_wpcom is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-instagram-gallery.php on line 23

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Mailchimp::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php on line 17

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Tweetstorm_Gather::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-tweetstorm-gather.php on line 21

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Tweetstorm_Gather::$is_wpcom is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-tweetstorm-gather.php on line 22

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Gutenberg_Available_Extensions::$wpcom_is_site_specific_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/gutenberg-available-extensions.php on line 20

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Memberships::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php on line 23

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Memberships::$wpcom_is_site_specific_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php on line 24

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Subscribers::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php on line 15

Deprecated: Creation of dynamic property Automattic\Jetpack\Sync\Queue::$random_int is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/vendor/automattic/jetpack-sync/src/class-queue.php on line 38

Deprecated: Creation of dynamic property Automattic\Jetpack\Sync\Queue::$random_int is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/vendor/automattic/jetpack-sync/src/class-queue.php on line 38

Deprecated: Creation of dynamic property WPCOM_Widget_Goodreads::$shelves is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/modules/widgets/goodreads.php on line 33

Deprecated: DateTime::__construct(): Passing null to parameter #1 ($datetime) of type string is deprecated in /var/www/twodee/blog/wp-includes/script-loader.php on line 348

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$toolbar_classic_block is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 347

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$toolbar_block is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 349

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$toolbar_block_side is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 350

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$panels_block is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 351

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$used_block_buttons is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 354

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198
» CS 268: Lecture 7 – Flexbox Continued

teaching machines

CS 268: Lecture 7 – Flexbox Continued

February 25, 2020 by . Filed under
Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383
lectures, spring-2020, webdev.

Dear students:

Last week we saw how we can use Flexbox to size and distribute our boxes of content across a container. Today we continue to explore Flexbox and see how to recreate some common layouts found across the web.

But first, let’s review Flexbox by completing an exercise.

Flexbox

Last time we looked at only the properties of the flex container. Let’s round out our discussion of Flexbox by looking at the flex children. The flex children may already be sized and position the way we want them by the properties set on the container. But if not, we can tweak them with several child properties.

By default, the children appear along the direction of flow in their order of expression. The order property can be used to override this. But certain tasks like tabbing through the elements will still traverse them in expression order, and in general, letting the visual order diverge from the structural order will lead to a poor user experience.

We alter the cross-axis alignment per child with the align-self property. For example, the parent might have each child stretch, but we override this for one of the children by setting align-self to center.

When the flex container has leftover space, that space by default will be portioned out according to the justify-content algorithm. Sometimes, however, we want the children to grow into the extra space. For that, we use the flex-grow property. Each element requests a number of “units” of this extra space. By default, each child requests 0 units. All the requests are summed together, and each child is awarded its computed proportion.

If only one child sets its flex-grow property to a non-zero number N, then it will be awarded N / N = 100% of the space. If there are two children each with flex-grow set to 1, each will be awarded 1/2 of the space.

Note that the flex-grow values are not the same as the relative sizes of the children—because before the same extra space is divided, the children are sized according to their flex-basis property. By default, flex-basis is set to auto, which means the children are sized according to their width or height properties first and only then given any extra space. If we truly want flex-grow to determine the relative size of each child, we can set flex-basis to 0 and let flex-grow expand the children.

If there’s not enough space for the children, space is taken away from according to their flex-shrink values. By default the shrink values are 1, meaning that each element loses the same amount of extra space. If we want a child to not shrink, we set it’s flex-shrink to 0.

There’s this shorthand rule for setting all three of the properties that size a child along the main axis:

.child {
  flex: GROW SHRINK BASIS;
}

Let’s apply these ideas to create some common layouts.

N-column

As an example of an n-column layout, consider CodePen. In fact, let’s just crudely recreate CodePen. We use this HTML structure:

<body>
  <div id="editor-root">
    <textarea id="html-editor" class="editor"></textarea>
    <textarea id="css-editor" class="editor"></textarea>
  </div>
  <iframe id="preview"></iframe>
</body>

We split the editor-root into two columns that get an equal share of the leftover space using these rules:

#editor-root {
  display: flex;
  flex-direction: row;
}

.editor {
  flex: 1;
}

We split the body into two rows, one of fixed height and one that grows using these rules:

html, body {
  height: 100%;
}

body {
  margin: 0;
  display: flex;
  flex-direction: column;
}

#editor-root {
  flex: 0 1 300px;
  /* ... */
}

#preview {
  flex: 1;
}

Let’s sneak in this Javascript so that edits to the text boxes actually generate a preview in the iframe:

let htmlEditor = document.getElementById('html-editor');
let cssEditor = document.getElementById('css-editor');
let preview = document.getElementById('preview');

function updatePreview() {
  preview.srcdoc = `
<html>
  <head>
    <title>Preview</title>
    <style>${cssEditor.value}</style>
  </head>
  <body>${htmlEditor.value}</body>
</html>`;
}

htmlEditor.addEventListener('input', updatePreview);
cssEditor.addEventListener('input', updatePreview);

Holy Grail

Another common layout we find on the web is the holy grail, which consists of five elements, much like Swing’s BorderLayout. There’s a header, footer, two sidebars, and a central area for content. This pattern is commonly seen on blogs.

We use the following structure:

<div id="root">
  <header>...</header>
  <div id="chester">
    <div id="left-arm">...</div>
    <div id="heart">...</div>
    <div id="right-arm">...</div>
  </div>
  <footer>...</footer>
</div>

Note that this layout is two-dimensional. Flexbox is mostly a tool for one-dimensional layouts. But we can nest them.

First, let’s get the content filling the window with these rules:

html, body {
  height: 100%;
}

body {
  margin: 0;
}

Then we style our outer root element to flow downward like this:

#root {
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

The middle or chester element we want to expand, and we also want it to lay out its children in a row, so we apply this style:

#chester {
  flex-grow: 1;

  display: flex;
  flex-direction: row;
  align-items: stretch;
}

We set the heart to take up any leftover space with this rule:

#heart {
  flex-grow: 1;
}

And we size the sidebars and keep them from shrinking with these rules:

#left-arm, #right-arm {
  flex-shrink: 0;
  flex-basis: 200px;
}

Wrapping

If the children of a flex container have all been shrunk to their utmost and there still is not enough room for them, they can be made to wrap along the cross axis using the flex-wrap property. Valid values include nowrap, wrap, and wrap-reverse. We’ll see these at work in Flexercise.

Activity

With exactly one neighbor, claim your task on Crowdsource. (Everyone will be assigned task 1.) Then recreate the following page:

Apply styling to the following starter code to match the page above:

<!DOCTYPE html>
<html>

<head>
  <title>Gallery</title>
  <style>

/* Add your CSS here. */

#root {
  width: 960px;
}

  </style>
</head>

<body>
  <div id="root">
    <div class="card"><img src="https://picsum.photos/200/300?random=1"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=2"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=3"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=4"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=5"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=6"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=7"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=8"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=9"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=10"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=11"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=12"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=13"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=14"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=15"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=16"></div>
    <div class="card"><img src="https://picsum.photos/200/300?random=17"></div>
  </div>
</body>

</html>

Notice how the content is centered. We have used Flexbox to achieve vertical and horizontal centering. To achieve horizontal centering only, we have another option:

Notice also the shadowing, which was achieved with the box-shadow property.

Submit your solution on Crowdsource.

TODO

Here’s your TODO list for next time:

See you next time.

Sincerely,

P.S. It’s time for a haiku!

Life is like Flexbox
Youth and work are flex: 0
The rest is old age

P.P.S. Here’s the code we wrote together in class…

codepen.html

<!DOCTYPE html>

<html lang="en">
<head>
  <title></title>
  <style>
html {
  height: 100%;
}

body {
  margin: 0;
  display: flex;
  flex-direction: column;
  height: 100%;
}

#editor-root {
  display: flex;
  flex-direction: row;
  flex-basis: 200px;
}

.editor {
  flex-grow: 1;
}

#preview {
  flex-grow: 1;
}

  </style>
</head>

<body>
  <div id="editor-root">
    <textarea id="html-editor" class="editor"></textarea>
    <textarea id="css-editor" class="editor"></textarea>
  </div>

  <iframe src="https://twodee.org" id="preview"></iframe>



  <script>

const htmlEditor = document.getElementById('html-editor');
const cssEditor = document.getElementById('css-editor');
const preview = document.getElementById('preview');

function updatePreview() {
  const html = `
<html>
  <head>
    <style>
      ${cssEditor.value}
    </style>
  </head>
  <body>
    ${htmlEditor.value}
  </body>
</html>
  `;
  console.log(html);
  preview.srcdoc = html;
}

htmlEditor.addEventListener('input', updatePreview);
cssEditor.addEventListener('input', updatePreview);

  </script>
</body>

</html>

holygrail.html

<!DOCTYPE html>

<html lang="en">
  <head>
    <title></title>
    <style>
html, body, #root {
  height: 100%;
}





body {
  margin: 0;
}

#root {
  display: flex;
  flex-direction: column;
}

#chester {
  flex-grow: 2;
  display: flex;
  flex-direction: row;
}

#left-arm {
  background-color: purple;
  flex-basis: 200px;
}

#right-arm {
  background-color: pink;
  flex-basis: 200px;
}

#torso {
  background-color: red;
  flex-grow: 1;
}

header {
  background-color: blue;
}

footer {
  background-color: green;
}

    </style>
  </head>

  <body>

    <div id="root">
      <header>header</header>
      <div id="chester">
        <div id="left-arm">left</div>
        <div id="torso">torso</div>
        <div id="right-arm">right</div>
      </div>
      <footer>footer</footer>
    </div>

  </body>
</html>