ma

Coronavirus | Chennai-based ayurvedic pharmacist dies after drinking concoction of his own preparation

Managing Director of the firm faints after tasting the chemical




ma

Come May 11, post-production work in films will resume

CM takes decision following representations from industry




ma

HC seeks report on sanitisation measures taken at temporary markets

The Madras High Court on Friday granted time till Monday for the State government to file a comprehensive report on steps taken to conduct mass testin




ma

On Day 2, Tasmac sales touch ₹140 cr.

The Tamil Nadu State Marketing Corporation (Tasmac) sold liquor worth ₹140 crore on the second day after it opened its outlets. A Tasmac source said t




ma

Ranipet police foil protest move against opening of Tasmac shop

Police personnel and staff of the Tamil Nadu State Marketing Corporation Limited foiled a protest attempt against the opening of a liquor shop at Rani




ma

Madras High Court orders closure of all Tasmac liquor shops in Tamil Nadu

The Madras High Court on Friday directed the State government to close all 3,850 liquor shops run by the Tamil Nadu State Marketing Corporation (Tasma




ma

[ASAP] Monochromatic X-ray Source Based on Scattering from a Magnetic Nanoundulator

ACS Photonics
DOI: 10.1021/acsphotonics.0c00121




ma

[ASAP] White Light Emission from a Zero-Dimensional Lead Chloride Hybrid Material

ACS Photonics
DOI: 10.1021/acsphotonics.9b01817




ma

[ASAP] Quasinormal-Mode Non-Hermitian Modeling and Design in Nonlinear Nano-Optics

ACS Photonics
DOI: 10.1021/acsphotonics.0c00014




ma

[ASAP] Directional off-Normal Photon Streaming from Hybrid Plasmon-Emitter Coupled Metasurfaces

ACS Photonics
DOI: 10.1021/acsphotonics.0c00196




ma

[ASAP] Goodbye Juan José Sáenz (1960–2020): A Bright Scientific Mind, an Unusually Prolific Friend, and a Family Man

ACS Photonics
DOI: 10.1021/acsphotonics.0c00526




ma

[ASAP] Near-Field Radiative Heat Transfer between Dissimilar Materials Mediated by Coupled Surface Phonon- and Plasmon-Polaritons

ACS Photonics
DOI: 10.1021/acsphotonics.0c00404




ma

[ASAP] Chip-Scale Reconfigurable Optical Full-Field Manipulation: Enabling a Compact Grooming Photonic Signal Processor

ACS Photonics
DOI: 10.1021/acsphotonics.0c00103




ma

[ASAP] Exciton-Polaritons with Magnetic and Electric Character in All-Dielectric Metasurfaces

ACS Photonics
DOI: 10.1021/acsphotonics.0c00063




ma

[ASAP] Probing the Radiative Electromagnetic Local Density of States in Nanostructures with a Scanning Tunneling Microscope

ACS Photonics
DOI: 10.1021/acsphotonics.0c00264




ma

[ASAP] Line-Scan Hyperspectral Imaging Microscopy with Linear Unmixing for Automated Two-Dimensional Crystals Identification

ACS Photonics
DOI: 10.1021/acsphotonics.0c00050




ma

Making a Better Custom Select Element

Julie Grundy kicks off this, our fifteenth year, by diving headlong into the snowy issue of customising form inputs. Nothing makes a more special gift at Christmas that something you’ve designed and customised yourself. But can it be done while staying accessible to every user?


In my work as an accessibility consultant, there are some frequent problems I find on people’s websites. One that’s come up a lot recently is that people are making custom select inputs for their forms. I can tell that people are trying to make them accessible, because they’ve added ARIA attributes or visually-hidden instructions for screen reader users. Sometimes they use a plugin which claims to be accessible. And this is great, I love that folks want to do the right thing! But so far I’ve never come across a custom select input which actually meets all of the WCAG AA criteria.

Often I recommend to people that they use the native HTML select element instead. Yes, they’re super ugly, but as Scott Jehl shows us in his article Styling a Select Like It’s 2019 they are a lot easier to style than they used to be. They come with a lot of accessibility for free – they’re recognised and announced clearly by all screen reader software, they work reliably and predictably with keyboards and touch, and they look good in high contrast themes.

But sometimes, I can’t recommend the select input as a replacement. We want a way for someone to choose an item from a list of options, but it’s more complicated than just that. We want autocomplete options. We want to put images in there, not just text. The optgroup element is ugly, hard to style, and not announced by screen readers. The focus styles are low contrast. I had high hopes for the datalist element, but although it works well with screen readers, it’s no good for people with low vision who zoom or use high contrast themes.

Figure 1: a datalist zoomed in by 300%

Select inputs are limited in a lot of ways. They’re frustrating to work with when you have something which looks almost like what you want, but is too restricted to be useful. We know we can do better, so we make our own.

Let’s work out how to do that while keeping all the accessibility features of the original.

Semantic HTML

We’ll start with a solid, semantic HTML base. A select input is essentially a text input which restricts the possible answers, so let’s make a standard input.

<label for="custom-select">User Type</label>
<input type="text" id="custom-select">

Then we need to show everyone who can see that there are options available, so let’s add an image with an arrow, like the native element.

<label for="custom-select">User Type</label>
<input type="text" id="custom-select">
<img src="arrow-down.svg" alt="">

For this input, we’re going to use ARIA attributes to represent the information in the icon, so we’ll give it an empty alt attribute so screen readers don’t announce its filename.

Finally, we want a list of options. An unordered list element is a sensible choice here. It also lets screen reader software understand that these bits of text are related to each other as part of a group.

<ul class="custom-select-options">
  <li>User</li>
  <li>Author</li>
  <li>Editor</li>
  <li>Manager</li>
  <li>Administrator</li>
</ul>

You can dynamically add or remove options from this list whenever you need to. And, unlike our <option> element inside a <select>, we can add whatever we like inside the list item. So if you need images to distinguish between lots of very similar-named objects, or to add supplementary details, you can go right ahead. I’m going to add some extra text to mine, to help explain the differences between the choices.

This is a good base to begin with. But it looks nothing like a select input! We want to make sure our sighted users get something they’re familiar with and know how to use already.

Styling with CSS

I’ll add some basic styles similar to what’s in Scott Jehl’s article above.

We also need to make sure that people who customise their colours in high contrast modes can still tell what they’re looking at. After checking it in the default Windows high contrast theme, I’ve decided to add a left-hand border to the focus and hover styles, to make sure it’s clear which item is about to be chosen.

This would be a good time to add any dark-mode styles if that’s your jam. People who get migraines from bright screens will thank you!

JavaScript for behaviour

Of course, our custom select doesn’t actually do anything yet. We have a few tasks for it: to toggle the options list open and closed when we click the input, to filter the options when people type in the input, and for selecting an option to add it to the input and close the list. I’m going to tackle toggling first because it’s the easiest.

Toggling

Sometimes folks use opacity or height to hide content on screen, but that’s like using Harry Potter’s invisibility cloak. No-one can see what’s under there, but Harry doesn’t cease to exist and you can still poke him with a wand. In our case, screen reader and keyboard users can still reach an invisible list.

Instead of making the content see-through or smaller, I’m going to use display: none to hide the list. display: none removes the content from the accessibility tree, so it can’t be accessed by any user, not just people who can see. I always have a pair of utility classes for hiding things, as follows:

.hidden-all {
  display: none;
}

.hidden-visually {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0,0,0,0);
    white-space: nowrap;
    -webkit-clip-path: inset(50%);
    clip-path: inset(50%);
    border: 0;
} 

So now I can just toggle the CSS class .hidden-all on my list whenever I like.

Browsing the options

Opening up our list works well for our mouse and touch-screen users. Our styles give a nice big tap target for touch, and mouse users can click wherever they like.

We need to make sure our keyboard users are taken care of though. Some of our sighted users will be relying on the keyboard if they have mobility or dexterity issues. Usually our screen reader users are in Browse mode, which lets them click the arrow keys to navigate through content. However, custom selects are usually inside form elements. which pushes screen reader software to Forms Mode. In Forms mode, the screen reader software can only reach focusable items when the user clicks the Tab key, unless we provide an alternative. Our list items are not focusable by default, so let’s work on that alternative.

To do this, I’m adding a tabindex of -1 to each list item. This way I can send focus to them with JavaScript, but they won’t be part of the normal keyboard focus path of the page.

csOptions.forEach(function(option) {
    option.setAttribute('tabindex, '-1')
}) 

Now I can move the focus using the Up and Down arrow keys, as well as with a mouse or tapping the screen. The activeElement property of the document is a way of finding where the keyboard focus is at the moment. I can use that to loop through the elements in the list and move the focus point forward or back, depending on which key is pressed.

function doKeyAction(whichKey) {
  const focusPoint = document.activeElement
  switch(whichKey) {
    case: 'ArrowDown':
      toggleList('Open')
      moveFocus(focusPoint, 'forward')
      break
    case: 'ArrowUp':
      toggleList('Open')
      moveFocus(focusPoint, 'back')
      break
  }
}

Selecting

The Enter key is traditional for activating an element, and we want to match the original select input.

We add another case to the keypress detector…

case 'Enter':
  makeChoice(focusPoint)
  toggleList('Shut')
  setState('closed')
  break 

… then make a function which grabs the currently focused item and puts it in our text input. Then we can close the list and move focus up to the input as well.

function makeChoice(whichOption) {
    const optionText = whichOption.documentQuerySelector('strong')
    csInput.value = optionText
}

Filtering

Standard select inputs have keyboard shortcuts – typing a letter will send focus to the first item in the option which begins with that letter. If you type the letter again, focus will move to the next option beginning with that letter.

This is useful, but there’s no clue to tell users how many options might be in this category, so they have to experiment to find out. We can make an improvement for our users by filtering to just the set of options which matches that letter or sequence of letters. Then sighted users can see exactly how many options they’ve got, and continue filtering by typing more if they like. (Our screen reader users can’t see the remaining options while they’re typing, but don’t worry – we’ll have a solution for them in the next section).

I’m going to use the .filter method to make a new array which only has the items which match the text value of the input. There are different ways you could do this part – my goal was to avoid having to use regex, but you should choose whatever method works best for your content.

function doFilter() {
  const terms = csInput.value
  const aFilteredOptions = aOptions.filter(option => {
    if (option.innerText.toUpperCase().startsWith(terms.toUpperCase())) {
    return true
    }
  })
  // hide all options
  csOptions.forEach(option => option.style.display = "none")
  // re-show the options which match our terms
  aFilteredOptions.forEach(function(option) {
    option.style.display = ""
  })
} 

Nice! This is now looking and behaving really well. We’ve got one more problem though – for a screen reader user, this is a jumble of information. What’s being reported to the browser’s accessibility API is that there’s an input followed by some clickable text. Are they related? Who knows! What happens if we start typing, or click one of the clicky text things? It’s a mystery when you can’t see what’s happening. But we can fix that.

ARIA

ARIA attributes don’t provide much in the way of additional features. Adding an aria-expanded='true' attribute doesn’t actually make anything expand. What ARIA does is provide information about what’s happening to the accessibility API, which can then pass it on to any assistive technology which asks for it.

The WCAG requirements tell us that when we’re making custom elements, we need to make sure that as a whole, the widget tells us its name, its role, and its current value. Both Chrome and Firefox reveal the accessibility tree in their dev tools, so you can check how any of your widgets will be reported.

We already have a name for our input – it comes from the label we associated to the text input right at the start. We don’t need to name every other part of the field, as that makes it seem like more than one input is present. We also don’t need to add a value, because when we select an item from the list, it’s added to the text input and therefore is exposed to the API.

Figure 2: How Firefox reports our custom select to assistive technology.

But our screen readers are going to announce this custom select widget as a text entry field, with some images and a list nearby.

The ARIA Authoring Practices site has a pattern for comboboxes with listboxes attached. It tells you all the ARIA you need to make screen reader software give a useful description of our custom widget.

I’m going to add all this ARIA via JavaScript, instead of putting it in the HTML. If my JavaScript doesn’t work for any reason, the input can still be a plain text field, and we don’t want screen readers to announce it as anything fancier than that.

csSelector.setAttribute('role', 'combobox') 
csSelector.setAttribute('aria-haspopup', 'listbox')
csSelector.setAttribute('aria-owns', '#list') 
csInput.setAttribute('aria-autocomplete', 'both')
csInput.setAttribute('aria-controls', 'list')

The next thing to do is let blind users know if the list is opened or closed. For that task I’m going to add an aria-expanded attribute to the group, and update it from false to true whenever the list changes state in our toggling function.

The final touch is to add a secret status message to the widget. We can use it to update the number of options available after we’ve filtered them by typing into the input. When there are a lot of options to choose from, this helps people who can’t see the list reducing know if they’re on the right track or not.

To do that we first have to give the status message a home in our HTML.

<div id='custom-select-status' class='hidden-visually' aria-live='polite'></div>

I’m using our visually-hidden style so that only screen readers will find it. I’m using aria-live so that it will be announced as often as it updates, not just when a screen reader user navigates past it. Live regions need to be present at page load, but we won’t have anything to say about the custom select then so we can leave it empty for now.

Next we add one line to our filtering function, to find the length of our current list.

updateStatus(aFilteredOptions.length)

Then we send that to a function which will update our live region.

function updateStatus(howMany) {
    console.log('updating status')
    csStatus.textContent = howMany + " options available."
}

Conclusion

Let’s review what we’ve done to make an awesome custom select input:

  • Used semantic HTML so that it’s easily interpreted by assistive technology while expanding the types of content we can include in it
  • Added CSS styles which are robust enough to survive different visual environments while also fitting into our branding needs
  • Used JavaScript to provide the basic functionality that the native element has
  • Added more JavaScript to get useful functionality that the native element lacks
  • Carefully added ARIA attributes to make sure that the purpose and results of using the element are available to assistive technology and are updated as the user interacts with it.

You can check out my custom select pattern on GitHub – I’ll be making additions as I test it on more assistive technology, and I welcome suggestions for improvements.

The ARIA pattern linked above has a variety of examples and customisations. I hope stepping through this example shows you why each of the requirements exists, and how you can make them fit your own needs.

I think the volume of custom select inputs out there shows the ways in which the native select input is insufficient for modern websites. You’ll be pleased to know that Greg Whitworth and Simon Pieters are working on improving several input types! You can let them know what features you’d like selects to have. But until that work pays off, let’s make our custom selects as accessible and robust as they can possibly be.


About the author

Julie Grundy is an accessibility expert who works for Intopia, a digital accessibility consultancy. She has over 15 years experience as a front-end web developer in the health and education sectors. She believes in the democratic web and aims to unlock digital worlds for as many people as possible. In her spare time, she knits very slowly and chases very quickly after her two whippets.

More articles by Julie




ma

Interactivity and Animation with Variable Fonts

Mandy Michael turns the corner on our variable font adventure and stumbles into a grotto of wonder and amazement. Not forgetting the need for a proper performance budget, Mandy shows how variable fonts can free your creativity from bygone technical constraints.


If you read Jason’s introductory article about variable fonts, you’ll understand the many benefits and opportunities that they offer in modern web development. From this point on we’ll assume that you have either read Jason’s introduction or have some prior knowledge of variable fonts so we can skip over the getting started information. If you haven’t read up on variable fonts before jump over to “Introduction to Variable Fonts: Everything you thought you knew about fonts just changed” first and then come join me back here so we can dive into using variable fonts for interactivity and animations!

Creative Opportunities

If we can use variable fonts to improve the performance of our websites while increasing the amount of style variations available to us, it means that we no longer need to trade off design for performance. Creativity can be the driving force behind our decisions, rather than performance and technical limitations.

Cookie text effect font: This Man is a Monster, by Comic Book Fonts.

My goal is to demonstrate how to create interactive, creative text on the web by combining variable fonts with CSS and JavaScript techniques that you may already be familiar with. With the introduction of variable fonts, designs which would have previously been a heavy burden on performance, or simply impossible due to technical limitations, are now completely possible.

Still I Rise Poem by Maya Angelou, Demo emphasising different words with variable fonts. View on Codepen.
Variable fonts demo with CSS Grid using multiple weights and font sizes to emphasise different parts of the message. View on Codepen.

The tone and intent of our words can be more effectively represented with less worry over the impacts of loading in “too many font weights” (or other styles). This means that we can start a new path and focus on representing the content in more meaningful ways. For example, emphasising different words, or phrases depending on their importance in the story or content.

Candy Cane Christmas Themed Text Effect with FS Pimlico Glow by Font Smith. View on Codepen.

Note: using variable fonts does not negate the need for a good web font performance strategy! This is still important, because after all, they are still fonts. Keep that in mind and check out some of the great work done by Monica Dinculescu, Zach Leatherman or this incredible article by Helen Homes.

Variable Fonts & Animations

Because variable fonts can have an interpolated range of values we can leverage the flexibility and interactive nature of the web. Rather than using SVG, videos or JavaScript to accomplish these effects, we can create animations or transitions using real text, and we can do this using techniques we may already be familiar with. This means we can have editable, selectable, searchable, copy-pastable text, which is accessible via a screenreader.

Grass Variable Font Demo

Growing Grass Variable Font Text. Demo on Codepen.

This effect is achieved using a font called Decovar, by David Berlow. To achieve the animation effect we only need a couple of things to get started.

First, we set up the font-family and make use of the new property font-variation-settings to access the different axes available in Decovar.

h1 {
  font-family: "Decovar";
  font-variation-settings: 'INLN' 1000, 'SWRM' 1000;
}

For this effect, we use two custom axis – the first is called “inline” and is represented by the code INLI and the second is “skeleton worm” represented by the code SWRM. For both axes, the maximum value is 1000 and the minimum value is 0. For this effect, we’ll make the most of the full axis range.

Once we have the base set up, we can create the animation. There are a number of ways to animate variable fonts. In this demo, we’ll use CSS keyframe animations and the font-variation-settings property, but you can also use CSS transitions and JavaScript as well.

The code below will start with the “leaves” expanded and then shrink back until it disappears.

@keyframes grow {
  0% {
    font-variation-settings: 'INLN' 1000, 'SWRM' 1000;
  }
  100% {
    font-variation-settings: 'INLN' 1000, 'SWRM' 0;
  }
}

Once we have created the keyframes we can add the animation to the h1 element, and that is the last piece needed in order to create the animation.

h1 {
  font-family: "Decovar";
  font-variation-settings: 'INLN' 1000, 'SWRM' 1000;
  animation: grow 4s linear alternate infinite;
}

What this demonstrates is that typically, to accomplish effects like this, the heavy lifting is done by the font. We really only need a few lines of CSS for the animation, which if you think about it, is pretty incredible.

There are all sorts of interesting, creative applications of variable fonts, and a lot of incredible fonts you can make the most of. Whether you want to create that “hand-writing” effect that we often see represented with SVG, or something a little different, there are a lot of different options.

Duos Writer: Hand Writing

Demo of hand writing variable font, Duos Writer by Underware.

Decovar: Disappearing Text

See the Pen CSS-only variable font demo using Decovar Regular by Mandy Michael (@mandymichael) on CodePen.

Cheee: Snow Text

Snow Text Effect - Text fills up with snow and gets “heavier” at the bottom as more snow gathers. Featuring “Cheee” by OhNoTypeCo. View on Codepen.

Variable Fonts, Media Queries and Customisation

It’s not that these are just beautiful or cool effects, what they demonstrate is that as developers and designers we can now control the font itself and that that means is that variable fonts allow typography on the web to adapt to the flexible nature of our screens, environments and devices.

We can even make use of different CSS media queries to provide more control over our designs based on environments, light contrast and colour schemes.

Though the CSS Media Queries Level 5 Spec is still in draft stages, we can experiment with the prefers-color-scheme (also known as dark mode) media query right now!

Dark Mode featuring Oozing Cheee by OhNoTypeCo

Oozing Dark Mode Text featuring “Cheee” by OhNoTypeCo. View Demo on Codepen.

The above example uses a font called “Cheee” by OhNoTypeCo and demonstrates how to make use of a CSS Transition and the prefers-color-scheme media query to transition the axis of a variable font.

h1 {
  font-family: “Cheee"
  font-variation-settings: "TEMP" 0;
  transition: all 4s linear;
}

@media (prefers-color-scheme: dark) {
  h1 {
    font-variation-settings: "TEMP" 1000;
  }
}

Dark mode isn’t just about changing the colours, it’s important to consider things like weight as well. It’s the combination of the weight, colour and size of a font that determines how legible and accessible it is for the user. In the example above, I’m creating a fun effect – but more practically, dark mode allows us to modify the contrast and styles to ensure better legibility and usability in different environments.

What is even more exciting about variable fonts in this context is that if developers and designers can have this finer control over our fonts to create more legible, accessible text, it also means the user has access to this as well. As a result, users that create their own stylesheets to customise the experience to their specific requirements, can now adjust the pages font weight, width or other available axis to what best suits them. Providing users with this kind of flexibility is such an incredible opportunity that we have never had before!

As CSS develops, we’ll have access to different environmental and system features that allow us to take advantage of our users unique circumstances. We can start to design our typography to adjust to things like screen width - which might allow us to tweak the font weight, width, optical size or other axes to be more readable on smaller or larger screens. Where the viewport is wide we can have more detail, when its smaller in a more confined space we might look at reducing the width of the font—this helps to maintain the integrity of the design as the viewport gets smaller or, to fit text into a particular space.

See the Pen CSS is Awesome - Variable fonts Edition. by Mandy Michael (@mandymichael) on CodePen.

We have all been in the situation where we just need the text to be slightly narrower to fit within the available space. If you use a variable font with a width axis you can slightly modify the width to adjust to the space available, and do so in a way that the font was designed to do, rather than using things like letter spacing which doesn’t consider the kerning of the characters.

Variable Fonts, JavaScript and Interactive Effects

We can take these concepts even further and mix in a little JavaScript to make use of a whole suite of different interactions, events, sensors and apis. The best part about this is whether you are using device orientation, light sensors, viewport resizes, scroll events or mouse movement, the base JavaScript doesn’t really change.

To demonstrate this, we’ll use a straightforward example – we’ll match our font weight to the size of our viewport – as the viewport gets smaller, the font weight gets heavier.

Demo: As the viewport width changes, the weight of the text “Jello” becomes heavier.

We’ll start off by setting our base values. We need to define the minimum and maximum axis values for the font weight, and the minimum and maximum event range, in this case the viewport size. Basically we’re defining the start and end points for both the font and the event.

// Font weight axis range
const minAxisValue = 200
const maxAxisValue = 900

// Viewport range
const minEventValue = 320px
const maxEventValue = 1440px

Next we determine the current viewport width, which we can access with something like window.innerWidth.

// Current viewport width
const windowWidth = window.innerWidth

Using the current viewport width value, we create the new scale for the viewport, so rather than the pixels values we convert it to a range of 0 - 0.99.

const windowSize = (windowWidth - minEventValue) / (maxEventValue - minEventValue)
// Outputs a value from 0 - 0.99

We then take that new viewport decimal value and use it to determine the font weight based on viewport scale.

const fontWeight = windowSize * (minAxisValue - maxAxisValue) + maxAxisValue;
// Outputs a value from 200 - 900 including decimal places

This final value is what we use to update our CSS. You can do this however you want – lately I like to use CSS Custom Properties. This will pass the newly calculated font weight value into our CSS and update the weight as needed.

// JavaScript
p.style.setProperty("--weight", fontWeight);

Finally, we can put all this inside a function and inside an event listener for window resize. You can modify this however you need to in order to improve performance, but in essence, this is all you need to achieve the desired outcome.

function fluidAxisVariation() {
  // Current viewport width
  const windowWidth = window.innerWidth

  // Get new scales for viewport and font weight
  const viewportScale = (windowWidth - 320) / (1440 - 320);
  const fontWeightScale = viewportScale * (200 - 900) + 900;

  // Set in CSS using CSS Custom Property
  p.style.setProperty("--weight", fontWeightScale);
}

window.addEventListener("resize", fluidAxisVariation);

You can apply this to single elements, or multiple. In this case, I’m changing the paragraph font weights and different rates, but also reducing the width axis of the headline so it doesn’t wrap onto multiple lines.

As previously mentioned, this code can be used to create all sorts of really amazing, interesting effects. All that’s required is passing in different event and axis values.

In the following example, I’m using mouse position events to change the direction and rotation of the stretchy slinky effect provided by the font “Whoa” by Scribble Tone.

See the Pen Slinky Text - WHOA Variable font demo by Mandy Michael (@mandymichael) on CodePen.

We can also take the dark mode/colour schemes idea further by making use of the Ambient Light Sensor to modify the font to be more legible and readable in low light environments.

This effect uses Tiny by Jack Halten Fahnestock from Velvetyne Type Foundry and demonstrates how we modify our text based by query the characteristics of the user’s display or light-level, sound or other sensors.

It’s only because Variable fonts give us more control over each of these elements that we can fine-tune the font characteristics to maximise the legibility, readability and overall accessibility of our website text. And while these examples might seem trivial, they are great demonstrations of the possibilities. This is a level of control over our fonts and text that is unprecedented.

Using device orientation to change the scale and weight of individual characters. View on Codepen.

Variable Fonts offer a new world of interactivity, usability and accessibility, but they are still a new technology. This means we have the opportunity to figure out how and what we can achieve with them. From where I stand, the possibilities are endless, so don’t be limited by what we can already do – the web is still young and there is so much for us to create. Variable fonts open up doors that never existed before and they give us an opportunity to think more creatively about how we can create better experiences for our users.

At the very least, we can improve the performance of our websites, but at best, we can make more usable, more accessible, and more meaningful content - and that, is what gets me really excited about the future of web typography with variable fonts.


About the author

Mandy is a community organiser, speaker, and developer working as the Front End Development Manager at Seven West Media in Western Australia. She is a co-organiser and Director of Mixin Conf, and the founder and co-organiser of Fenders, a local meetup for front-end developers providing events, mentoring and support to the Perth web community.

Mandy’s passion is CSS, HTML and JS and hopes to inspire that passion in others. She loves the supportive and collaborative nature of the web and strives to encourage this environment through the community groups she is a part of. Her aim is to create a community of web developers who can share, mentor, learn and grow together.

More articles by Mandy




ma

Making Distributed Working Work

Anna Debenham harnesses up the huskies and puts them to work to figure out how teams distributed across multiple locations can work effectively to all pull in the same direction. With modern workforces distributed from north pole to south, can they all be kept running in step?


Four years ago, I started working at a small startup called Snyk that’s based in two locations – London and Tel Aviv. The founders made it clear they wanted to grow headcount in both locations at the same rate, and for the design and engineering skillsets between the two offices to be evenly spread. We’re now at over 200 people and we’re still staying true to that vision, but only by completely changing how we were used to working.

The trend for fully distributed teams is on the rise – companies like InVision and GitLab have entirely remote employees. Snyk is somewhere in between, with small hubs of global team members in homes and shared offices globally alongside our main London, Tel Aviv, Boston, Ottawa and Bay Area offices.

Our R&D teams are based entirely in London or Tel Aviv, with a few employees working around Europe. Rather than have Team A working in one office and Team B working in another, we’ve deliberately designed it so that no R&D team at Snyk has all its members in one location. We could design our teams to be all co-located so that everyone’s in the same room, but we don’t.

When I explain this setup to people, I’ll often get a response of bewilderment – why do it this way? It sounds like a pain! Increasingly though, the reaction is positive – usually from people who’ve worked in a distributed team before where departments are split neatly between locations. They’ve experienced an “us vs them” culture, with work being thrown over the fence to designers or engineers in different timezones. They’ve been at the mercy of the decision makers who are all in the head office. This is exactly what we wanted to avoid. We wanted the company to feel like one team, across many locations.

It’s not perfect – I do miss the things that working in the same location brings such as collaborating on a whiteboard, or having planning documents stuck on the wall for the team to refer to. Pre-distributed working, I used to sit next to a designer and we’d bounce ideas off each other. Now I have to make the extra effort to schedule something in. Managing people remotely is also tough – I can’t easily see that a team member is having a bad day and make them a cup of tea.

But on the whole, it works pretty well for us. The time difference between London and Tel Aviv is a comfy 2 hours, and in Tel Aviv, the week runs from Sunday to Thursday, meaning there’s just a single day in the week when all our teams aren’t working. This makes the week feel like the ebb and flow of a tide – my Mondays are very busy, but on Fridays, half the team is off so there are barely any meetings – ideal for deep focus time.

So how do we make this distributed-but-also-co-located hybrid thing work?

Level the playing field

Firstly, that “us vs them” mentality I mentioned is the key thing to avoid to maintain a positive distributed work culture. Avoid the term “remote team”, as that has a sense of otherness. Instead, refer to your team as “distributed”. It’s such a small change that has the effect of bringing everyone onto the same level.

Also, consider your video conferencing etiquette – if you’ve got a large part of your team in one location, with just one or two members who are dialling in, you could end up with a very one-sided conversation. The room with the most people in it has a habit of forgetting the person they can’t easily see. Even if you’re in the same room, dial in individually so that everyones faces are the same size, and you’re addressing all the participants rather than just those in the same room as you.

Invest in tools that help communication

Early on, we invested in tools that would help make communication between locations as seamless as possible. I’m not talking about those screens with wheels that follow co-workers around a room to recreate a manager breathing down their neck (although now I think of it…). I’m talking about the familiar ones like Slack, Zoom and Notion.

Use a single tool where possible to reduce friction between teams so there’s no confusion as to whether you’re having a call over Google Hangouts, Zoom, Skype or whatever else is fashionable to use this year. Same with meeting notes – keep them in one place rather than scattered across Dropbox, Email and Google Docs.

Remote pair programming has also got a lot easier. We used ScreenHero before it got acquired and lost its remote control functionality – but there are some great alternatives out there like USE Together. You might also have collaboration tools built into your code editor, like Visual Studio’s Live Share, and Atom’s Teletype.

If teams are complaining about bad audio, don’t skimp – invest in better microphones, speakers and sound-proofing. You won’t get the benefits of working as a distributed team if there’s a barrier between communication. Ensure the internet is stable in all locations. Also, it sounds basic but make sure teams have somewhere to take a call in the first place, particularly 1:1s which shouldn’t be done in the open. Previous places I’ve contracted at had people dialling into meetings in stairwells, shower rooms and even toilet cubicles. Take care not to make the experience of working in a distributed team end up harming the experience of working in an office.

Open a window

For as long as we’ve had offices, we’ve had a fixed camera and TV screen setup between them that acts as a “window” between locations. The camera is on all the time, and we turn the microphone on once a day for standup (or whenever someone wants to say hi). When I turn on the TV in the morning, I can see the Tel Aviv office already working. At midday, our Boston office comes online, followed shortly after by our Ottawa office. It’s incredible what a difference this has made to make us feel more like one office.

We’ve positioned one of the cameras next to our dining area so we can eat together. Another camera is honed in on a dog bed in the corner of the office (sometimes there’s a dog in it!).

Distributed meetings

With the time differences and weekday shift, there’s a condensed timeframe in which we can collaborate. It’s not as bad as it could be (I pity my fellow Londoners who work for companies based in California), but the hours between 9am and 4pm Monday to Thursday for us are at a premium. This means the meetings we have need to be a good use of everyone’s time. When we can’t find a time that works for everyone, we record the meeting. But even if everyone can make it, we still take notes.

The notebook brand Field Notes have a slogan “I’m not writing it down to remember it later, I’m writing it down to remember it now.”. This is a reminder that it’s not always the notes themselves that are useful, but the act of taking them. Where they’re really powerful is when you share them in real time. In Kevin Hoffman’s book ‘Meeting Design’, he recommends the notetaker shares their screen while taking notes so that everyone can participate in making sure those notes are accurate. Having the notes on the screen also helps focus the conversation – particularly if you have an agenda template to start with. It means you’ve got a source of truth for someone who mis-remembers a conversation, and you’ve got something to look back on in the next meeting so you don’t repeat yourselves.

Another tip we’ve taken from Kevin’s book is to have a kanban board for standing meetings, where everyone can add a topic. That way, you always have a backlog of topics to discuss in the meeting. If there aren’t any, you can cancel the meeting!

We use Notion’s kanban template for our sync meeting notes. Anyone can add a topic before (or during) the meeting and we go through each of them in order. We add notes and action points to the topic card.

Don’t get into bad habits when you’re lucky enough to be sharing a single space – keep documenting conversations and decisions in the same way you would with a distributed team, so that future you can remember, and future team members can gather that context.

Team bonding

I always think the best way to bonding with people is over a meal – isn’t that what Christmas dinner is great for? As a distributed team, we can’t do that. We could try and recreate it (even just for the comedy value), but it’s really not the same. We have to try something different.

Enter Eurovision. For those of you outside Europe, imagine a cheesy pop song contest where each country performs their own song and everyone votes for the winner. This year, it was held in Tel Aviv, so dozens of us sat down to watch the live stream. We set up a Eurovision Slack channel and shared our horror in real time.

But Eurovision only happens ones a year, so we’ve extended shared experiences into multiple “hobby” Slack channels: we have one for food fans (#fun-foodies), football fans (#fun-footies), and even sourdough fans (#fun-sourdough). There’s also a weekly “drink and sync” where office-less team members join a video call and chat over a beer, coffee, or juice depending on the time of day for those that dial in. One team runs a movie club where they choose a video that’s relevant to their team’s work (such as a conference talk) and watch it together at the same time.

Onboarding new team members can feel quite impersonal if their manager isn’t in the same office. Starting your first day in an office full of strangers, where the only interaction with your manager is over a video call can feel daunting. And as a manager, I get anxious about my new hire’s first day – was there someone there to greet them and show them where they sit? Was everything set up for them? Did they have someone to eat lunch with? So we’ve been rolling out an “onboarding buddy” scheme. This is someone local who can help the new hire settle in to their new surroundings. It’s someone to chat to, share a coffee with, and generally look out for them.

We also use a Slack app called Donut which pairs employees up for informal chats to get to know each other. You get paired with someone random in the company and it helps you schedule a call with them. This is to encourage cross-pollination across teams and locations.

What distributed teamwork has taught us

There’s a lot that we’ve learnt about working well as a distributed team. We try and recreate the good things about sharing a physical space, and make them feel just as natural in the digital space, while also compensating for the lack of intimacy from being thousands of miles apart.

Mel Choyce’s 24 ways article Surviving—and Thriving—as a Remote Worker stresses the value of remote working, and the long term benefits it has had.

Working remotely has made me a better communicator largely because I’ve gotten into the habit of making written updates.

I think in a lot of ways, the distance has brought us closer. We make more of an effort to check in on how each other is doing. We document as much as we can, which really helps new hires get up to speed quickly.

By identifying what we find valuable about working in the same room, and translating that to work across locations, we find collaboration easier because we’re no longer strangers to each other. We might not be able to have those water-cooler moments in the physical realm, but we’ve done a good job of replicating that online.


About the author

Anna Debenham lives in London and is a Product Manager at Snyk.

She’s the author of Front-end Style Guides, and when she’s not playing on them, she’s testing as many game console browsers as she can get her hands on.

More articles by Anna




ma

Flexible Captioned Slanted Images

Eric Meyer gift wraps the most awkwardly shaped of boxes using nothing but CSS, HTML and a little curl of ribbon. No matter how well you plan and how much paper you have at your disposal, sometimes you just need to slant the gift to the side.


We have a lot of new layout tools at our disposal these days—flexbox is finally stable and interoperable, and Grid very much the same, with both technologies having well over 90% support coverage. In that light, we might think there’s no place for old tricks like negative margins, but I recently discovered otherwise.

Over at An Event Apart, we’ve been updating some of our landing pages, and our designer thought it would be interesting to have slanted images of speakers at the tops of pages. The end result looks like this.

The interesting part is the images. I wanted to set up a structure like the following, so that it will be easy to change speakers from time to time while preserving accessible content structures:

<div id="page-top">
  <ul class="monoliths">
    <li>
      <a href="https://aneventapart.com/speakers/rachel-andrew"> 
        <img src="/img/rachel-andrew.jpg" alt=""> 
        <div> 
          <strong>Rachel Andrew</strong> CSS Grid 
        </div> 
      </a>
    </li>
    <li>
      <a href="https://aneventapart.com/speakers/derek-featherstone"> 
        <img src="/img/derek-featherstone.jpg" alt=""> 
        <div> 
          <strong>Derek Featherstone</strong> Accessibility 
        </div> 
      </a>
    </li>
    <li>
      …
    </li>
    <li>
      …
    </li>
  </ul>
</div>

The id value for the div is straightforward enough, and I called the ul element monoliths because it reminded me of the memorial monoliths at the entrance to EPCOT in Florida. I’m also taking advantage of the now-ubiquitous ability to wrap multiple elements, including block elements, in a hyperlink. That way I can shove the image and text structures in there, and make the entire image and text below it one link.

Structure is easy, though. Can we make that layout fully responsive? I wondered. Yes we can. Here’s the target layout, stripped of the navbar and promo copy.

So let’s start from the beginning. The div gets some color and text styling, and the monoliths list is set to flex. The images are in a single line, after all, and I want them to be flexible for responsive reasons, so flexbox is 100% the right tool for this particular job.

#page-top { 
  background: #000; 
  color: #FFF; 
  line-height: 1; 
} 
#page-top .monoliths { 
  display: flex; 
  padding-bottom: 1em; 
  overflow: hidden; 
}

I also figured, let’s give the images a simple basis for sizing, and set up the hyperlink while we’re at it.

#page-top .monoliths li { 
  width: 25%; 
} 
#page-top .monoliths a { 
  color: inherit; 
  text-decoration: inherit; 
  display: block; 
  padding: 1px; 
}

So now the list items are 25% wide—I can say that because I know there will be four of them—and the links pick up the foreground color from their parent element. They’re also set to generate a block box.

At this point, I could concentrate on the images. They need to be as wide as their parent element, but no wider, and also match height. While I was at it, I figured I’d create a little bit of space above and below the captioning text, and make the strong elements containing speakers’ names generate a block box.

#page-top .monoliths img { 
  display: block; 
  height: 33rem; 
  width: 100%; 
} 
#page-top .monoliths div { 
  padding: 0.5em 0; 
} 
#page-top .monoliths strong { 
  display: block; 
  font-weight: 900; 
}

It looks like the speakers were all cast into the Phantom Zone or something, so that needs to be fixed. I can’t physically crop the images to be the “correct” size, because there is no correct size: this needs to work across all screen widths. So rather than try to swap carefully-sized images in and out at various breakpoints, or complicate the structure with a wrapper element set to suppress overflow of resized images, I turned to object-fit.

#page-top .monoliths img { 
  display: block; 
  height: 33rem; 
  width: 100%; 
  object-fit: cover; 
  object-position: 50% 20%; 
}

If you’ve never used object-fit, it’s a bit like background-size. You can use it to resize image content within the image’s element box without creating distortions. Here, I set the fit sizing to cover, which means all of the img element’s element box will be covered by image content. In this case, it’s like zooming in on the image content. I also set a zooming origin with object-position, figuring that 50% across and 20% down would be in the vicinity of a speaker’s face, given the way pictures of people are usually taken.

This is fairly presentable as-is—a little basic, perhaps, but it would be fine to layer the navbar and promo copy back over it with Grid or whatever, and call it a day. But it’s too square and boxy. We must go further!

To make that happen, I’m going to take out the third and fourth images temporarily, so we can see more clearly how the next part works. That will leave us with Rachel and Derek.

The idea here is to clip the images to be slanted, and then pull them close to each other so they have just a little space between them. The first part is managed with clip-path, but we don’t want to pull the images together unless their shapes are being clipped. So we set up a feature query.

@supports (clip-path: polygon(0 0)) or (-webkit-clip-path: polygon(0 0)) { 
  #page-top .monoliths li { 
    width: 37.5%; 
  } 
}

I decided to test for both the un-prefixed and WebKit-prefixed versions of clip-path because Safari still requires the prefix, and I couldn’t think of a good reason to penalize Safari’s users for the slowness of its standards advancement. Then I made the images wider, taking them from 25% to 37.5%, which makes them half again as wide.

Thanks to object fitting, the images don’t distort when I change their parent’s width; they just get wider and scale up the contents to fit. And now, it is time for clipping!

@supports (clip-path: polygon(0 0)) or (-webkit-clip-path: polygon(0 0)) { 
  #page-top .monoliths li { 
    width: 37.5%; 
    -webkit-clip-path: polygon(25% 0, 100% 0, 75% 100%, 0 100%); 
    clip-path: polygon(25% 0, 100% 0, 75% 100%, 0 100%); 
  } 
}

Each coordinate pair in the polygon() is like the position pairs in background-position or object-position: the horizontal distance first, followed by the vertical distance. So the first point in the polygon is 25% 0, which is 25% of the way across the element box, and no distance down, so right at the top edge. 100% 0 is the top right corner. 75% 100% is on the bottom edge, three-quarters of the way across the element, and 0 100% is the bottom left corner. That creates a polygon that’s a strip three-quarters the full width of the element box, and runs from bottom left to top right.

Now we just have to pull them together, and this is where old tricks come back into play: all we need is a negative right margin to bring them closer together.

#page-top .monoliths li { 
  width: 37.5%; 
  margin-right: -7.5%; 
  -webkit-clip-path: polygon(25% 0, 100% 0, 75% 100%, 0 100%); 
  clip-path: polygon(25% 0, 100% 0, 75% 100%, 0 100%); 
}

The separation between them is a little wider than we were originally aiming for, but let’s see what happens when we add the other two images back in and let flexbox do its resizing magic.

Notice how the slants actually change shape as the screen gets narrower or wider. This is because they’re still three-quarters the width of the image element’s box, but the width of that box is changing as the screen width changes. That means at narrow widths, the slant is much steeper, whereas at wide widths, the slant is more shallow. But since the clipping path’s coordinates were all set with percentage distances, they all stay parallel to each other while being completely responsive to changes in screen size. An absolute measure like pixels would have failed.

But how did the images get closer together just by adding in two more? Because the list items’ basic sizing added up to more than 100%, and they’re all set to flex-shrink: 1. No, you didn’t miss a line in the CSS: 1 is the default value for flex-shrink. Flex items will shrink by default, which after all is what we should expect from a flexible element. If you want to know how much they shrunk, and why, here’s what Firefox’s flex inspector reports.

When there were only two list items, there was space enough for both to be at their base size, with no shrinkage. Once we went to four list items, there wasn’t enough space, so they all shrank down. At that point, having a negative right margin of -7.5% was just right to pull them together to act as a unit.

So, now they’re all nicely nestled together, and fully responsive! The captions need a little work, though. Notice how they’re clipped off a bit on the left edge, and can be very much clipped off on the right side at narrower screen widths? This happens because the li elements are being clipped, and that clipping applies to all their contents, images and text alike. And we can’t use overflow to alter this: clipped is clipped, not overflowed.

Fortunately, all we really need to do is push the text over a small amount. Inside the feature query, I added:

#page-top .monoliths div { 
  padding-left: 2%;
  padding-right: 26%; 
}

This shifts the text just a bit rightward, enough to clear the clip path. On the right side, I padded the div boxes so their contents wouldn’t fall outside the clipped area and appear to slide under the next caption. We could also use margins here, but I didn’t for reasons I’ll make clear at the end.

At the last minute, I decided to make the text at least appear to follow the slants of the images. For that, I just needed to shift the first line over a bit, which I did with a bit more padding.

#page-top .monoliths strong { 
  padding-left: 1%; 
}

That’s all to the good, but you may have noticed the captions still overlap at really narrow screen widths. There are a lot of options here, from stacking the images atop one another to reverting to normal flow, but I decided to just hide the captions if things got too narrow. It reduces clutter without sacrificing too much in the way of content, and by leaving them still technically visible, they seem to remain accessible.

@media (max-width: 35rem) { 
  #page-top .monoliths div { 
    opacity: 0.01 
  } 
}

And that, as they say, is that! Fully responsive slanted images with text, in an accessible markup structure. I dig it.

I did fiddle around with the separations a bit, and found that a nice thin separator occurred around margin-right: -8%, whereas beefier ones could be found above -7%. And if you crank the negative margin value to something beyond -8%, you’ll make the images overlap entirely, no visible separation—which can be a useful effect in its own right.

I promised to say why I used padding for the caption text div rather than margins. Here’s why.

#page-top .monoliths div { 
  padding-left: 3%; 
  padding-right: 26%; 
  border-top: 2px solid transparent; 
  background: linear-gradient(100deg,hsl(292deg,50%,50%) 50%, transparent 85%); 
  background-clip: padding-box; 
}

It required a wee bit more padding on the left to look decent, and an alteration to the background clipping box in order to keep the purple from filling the transparent border area, but the end result is pretty nifty, if I do say so myself. Alternatively, we could drop the background gradient on the captions and put one in the background, with a result like this.

I have no doubt this technique could be extended, made more powerful, and generally improved upon. I really wished for subgrid support in Chrome, so that I could put everything on a grid without having to tear the markup structure apart, and there are doubtless even more interesting clipping paths and layout patterns to try out.

I hope these few ideas spark some much better ideas in you, and that you’ll share them with us!


About the author

Eric A. Meyer (@meyerweb) has been a burger flipper, a college webmaster, an early blogger, one of the original CSS Samurai, a member of the CSS Working Group, a consultant and trainer, and a Standards Evangelist for Netscape. Among other things, Eric co-wrote Design For Real Life with Sara Wachter-Boettcher for A Book Apart and CSS: The Definitive Guide with Estelle Weyl for O’Reilly, created the first official W3C test suite, assisted in the creation of microformats, and co-founded An Event Apart with Jeffrey Zeldman. Eric lives with his family in Cleveland, Ohio, which is a much nicer city than you’ve probably heard. He enjoys a good meal whenever he can and considers almost every form of music to be worthwhile.

More articles by Eric




ma

The effects of e-cigarette taxes on e-cigarette prices and tobacco product sales [electronic resource] : evidence from retail panel data / Chad D. Cotti, Charles J. Courtemanche, Johanna Catherine Maclean, Erik T. Nesson, Michael F. Pesko, Nathan Tefft

Cambridge, Mass. : National Bureau of Economic Research, 2020




ma

Cigarette taxes and teen marijuana use [electronic resource] / D. Mark Anderson, Kyutaro Matsuzawa, Joseph J. Sabia

Cambridge, Mass. : National Bureau of Economic Research, 2020




ma

MANHATTAN COM. ACCESS, ET AL. v. HALLECK, DEEDEE, ET AL.. Decided 06/17/2019




ma

AMERICAN LEGION, ET AL. v. AMERICAN HUMANIST ASSN., ET AL.. Decided 06/20/2019




ma

GUNDY, HERMAN A. v. UNITED STATES. Decided 06/20/2019




ma

KNICK, ROSE MARY v. SCOTT, PA, ET AL.. Decided 06/21/2019




ma

UNITED STATES v. DAVIS, MAURICE L., ET AL.. Decided 06/24/2019




ma

FOOD MARKETING INSTITUTE v. ARGUS LEADER MEDIA. Decided 06/24/2019




ma

European socialism: a concise history with documents / William Smaldone

Dewey Library - HX236.5.S6293 2020




ma

The scientist and the spy: a true story of China, the FBI, and industrial espionage / Mara Hvistendahl

Dewey Library - HV7561.H85 2020




ma

Reluctant warriors: Germany, Japan, and their U.S. alliance dilemma / Alexandra Sakaki, Hanns W. Maull, Kerstin Lukner, Ellis S. Krauss, Thomas U. Berger

Dewey Library - UA710.S135 2020




ma

Also serving time: Canada's provincial and territorial correctional officers / Rosemary Ricciardelli

Dewey Library - HV9506.R53 2019




ma

Democracy Incorporated: Managed Democracy and the Specter of Inverted Totalitarianism - New Edition / Sheldon S. Wolin

Online Resource




ma

Red state blues: how the conservative revolution stalled in the states / Matt Grossmann

Dewey Library - JK2356.G76 2019




ma

Primary elections in the United States / Shigeo Hirano, Columbia University ; James M. Snyder, Jr., Harvard University

Dewey Library - JK2071.H57 2019




ma

Human rights, ownership, and the individual / Rowan Cruft

Dewey Library - JC571.C78 2019




ma

Human rights in twentieth-century Australia / Jon Piccini

Dewey Library - JC599.A8 P53 2019




ma

How to democratize Europe / Stephanie Hennette, Thomas Piketty, Guillaume Sacriste, Antoine Vauchez

Online Resource




ma

Prisoners of politics: breaking the cycle of mass incarceration / Rachel Elise Barkow

Online Resource




ma

Homeland security and public safety: research, applications and standards / editors, Philip J. Mattson and Jennifer L. Marshall

Barker Library - UA23.H538 2019




ma

Why they marched: untold stories of the women who fought for the right to vote / Susan Ware

Dewey Library - JK1896.W37 2019




ma

Arendt on the political / David Arndt, Saint Maryʹs College, California

Dewey Library - JC251.A74 A83 2019




ma

Automation and utopia: human flourishing in a world without work / John Danaher

Online Resource




ma

The suspect: an Olympic bombing, the FBI, the media, and Richard Jewell, the man caught in the middle / Kent Alexander & Kevin Salwen

Dewey Library - HV8079.B62 A44 2019




ma

Reclaiming Liberalism David F. Hardwick, Leslie Marsh, editors

Online Resource




ma

The lost soul of the American presidency: the decline into demagoguery and the prospects for renewal / Stephen F. Knott

Dewey Library - JK511.K66 2019




ma

Managing interdependencies in federal systems: intergovernmental councils and the making of public policy / Johanna Schnabel

Online Resource




ma

We are indivisible: a blueprint for democracy after Trump / Leah Greenberg and Ezra Levin ; [foreword by Marielena Hincapié]

Dewey Library - JC423.G74 2019




ma

Militarization: a reader / Roberto J. González, Hugh Gusterson, Gustaaf Houtman, editors ; in collaboration with Catherine Besteman, Andrew Bickford, Catherine Lutz, Katherine T. McCaffrey, Austin Miller, David H. Price, David Vine

Dewey Library - U21.2.M558 2019




ma

A republic of equals: a manifesto for a just society / Jonathan Rothwell

Dewey Library - JC575.R68 2019