Web design resources?

I have found that the hardest part of doing web development is actually getting the design right. There are a ton of themes out there, but they are all based on bootstrap and are quite verbose and hard to tweak if they don’t fit your needs 100%.

On the other hand, I find starting from scratch quite daunting - even though I have read a couple of books on design (The Non-Designers Design Book is awesome!).

Note, I’m not talking about CSS frameworks; more like layout guidelines. Getting the micro-designs correct is easy - buttons, dropdowns etc. are easily stylable nowadays. So is actually implementing the layout; flexbox is widely supported and easy to reason with. It’s actually coming up with a decent layout that serves the application or website needs. Then finding a color scheme or a visual palette etc.

Of course, if there’s a decent CSS framework out there that provides some of this and is easily customizable, I’d be happy to know about it, but I’m looking for books, articles, examples on the design process.

6 Likes

Visual design… a huge topic…

Over the years, I’ve come to approach web design as a mixture of 1. industrial design (functionality) & 2. graphic design (emotional impact). Ideally you will find a balance between something memorable, yet easy-to-use.

Some topics to explore for 1) can include information design / information architecture.

For 2), ultimately the highest level of abstraction seems to be psychological mechanisms. Why does red invoke a certain reaction in many cultures? Why does the “rule-of-thirds” seem to invoke tension and energy? etc etc. It’s hard to recommend any single published resource here, there are so many.

Anyway, perhaps these areas might be worth exploring:

Mobile-first: Approach your project via a mobile-first design. The small screen /design constraints will force you to analyze what is really important. When you move up to a larger screen device, you can incrementally add design elements.

Affordance: One of the most interesting UX/UI ideas I’ve seen lately. It has its roots in cognitive psychology. Design to “afford the act of X”, via active learning and guiding the user.

Triggers and Goals: Zurb, the company behind Foundation (a CSS framework similar to Bootstrap), has an interesting section listing a variety of visual metaphors and their related emotional and psychological mechanisms. It might be worthwhile to explore it and see if it makes sense to you:
http://zurb.com/triggers

Practically, I would stick to Bootstrap, as it’s been battle-tested over the years and is robust. I am currently redoing our website – it would be insanity to try to code raw CSS to cover all the use-cases…

4 Likes

At my job we have Bootstrap on the older things, but have been setting up with Material on the newer things (via things like Polymer and such).

3 Likes

Some topics to explore for 1) can include information design / information architecture.

+1 to “web design” being about more than layout or CSS.

If you really want to understand “design”, here are some classics:

“The Design of Everyday Things” by Don Norman

“The Humane Interface” by Jef Raskin

“The Elements of User Experience” by Jesse James Garrett

“Don’t Make Me Think” by Steve Krug

“The Inmates Are Running the Asylum” by Alan Cooper

Search on “UX” (User eXperience) and “IA” (Information Architecture)
and you’ll find a lot more - it’s kind of a huge field :slight_smile:

4 Likes

In addition to learning the fundamentals of design/UX/IA I would recommend apps like Sketch and Affinity Designer that are more geared towards modern web/app design.

Sketch is easier to use, AD is more like Illustrator (but still easier than Illustrator). There are also lots of videos and tutorials about these apps which will teach you a lot about modern design as well.

2 Likes

I use Sketch heavily and love it. I mostly use it for designing icons and such but it can definitely be used for a mockup.

1 Like

Built for designing.

Create fast loading, highly readable, and 100% responsive interfaces with as little css as possible.

2 Likes

Affinity Designer looks really nice do you use it instead of Illustrator?

1 Like

I’ve only just bought it - so hope to soon :003:

(If you were asking generally, then yes, it is an Illustrator replacement - check this out: http://blog.iconfinder.com/compare-adobe-illustrator-affinity-designer-sketch-2016)

1 Like

I’m going to check that out, I’ve already tried Bulma.io, Foundation and Semantic UI but none seems to be better than Bootstrap for me.

Another thought, it might help if you can analyze the business requirements before starting the design process. This entails exploring the target market, writing up user scenarios, creating storyboards, etc. Understand your customer base, how you can categorize them, their different preferences, etc. It all matters.

Just as with software development, starting with a set of requirements makes explicit the constraints in your project and gives you direction. Otherwise things are too nebulous and vague. Also, try to set things up so you can iterate quickly, creating working mock-ups and adjusting them based on feedback, again and again.

Awhile ago I read a fantastic article about how Airbnb thinks about their different customer groups in terms of “customer scenarios” and storyboarding. They mention it serves as the overall basis for their entire marketing:

2 Likes

Whoa, I personally wouldn’t recommend that… one of my front-end designer explored it once, it has great ideas (functional CSS FTW!), but wait a bit until your HTML files are full of cryptic classnames. You’ll then have a lot of onboardings to do :slight_smile: I don’t think “highly readable” translates much to tachyons.

1 Like

Thanks everyone, a lot of helpful responses here.

I have indeed already read “The Design of Everyday Things”, “Don’t Make Me Think” and “The Inmates Are Running the Asylum”. Those are quite helpful when reviewing an interface, but not very helpful when actually designing one.

I have too bought Affinity Designer, it’s interesting. I haven’t tried Sketch yet.

I still feel though like the basic core of my question is not yet addressed in this topic:

  1. I have an idea for a small web application
  2. I write down a description of the core “screens” of the application (desired functionality, some core elements)
  3. I open a design tool or get a blank piece of paper
  4. ??? <- here is where I get stuck.

It is true that with mobile design, the screen is so small that you are forced to reach into well-established paradigms: A master-detail list, a tab controller etc. For the larger screens though you are on your own. For the scrollable and resizable screens the complexity skyrockets…

1 Like

I’ve been using webcomponents and (fake) shadow DOMs to do the css, so for example I have one thing that look like:

<dom-module id="my-notifications">
  <template>
    <style>
    swipe-action {
      --swipe-action-swipe-target: {
        position: relative;
      };
      display: block;
      margin: 8px;
    }

    paper-card {
      display: block;
      --paper-card-header: {
        height: 50px;
      };
      --paper-card-header-text: {
        font-size: medium;
      };
      --paper-card-content: {
        font-size: small;
      };
      --paper-card-actions: {
        font-size: small;
      };
    }

    .disable-selecting {
      -moz-user-select: none;
      -ms-user-select: none;
      -webkit-user-select: none;
      user-select: none;
      cursor: default;
    }
    </style>

    <phoenix-channel
      socket="{{socket}}"
      channel="{{notificationsChannel}}"
      topic-pre="spa:"
      topic="notifications"
      connected="{{isConnected}}"
      error="{{channelError}}"
      connect
      ></phoenix-channel>
    <phoenix-channel-msg
      channel="{{notificationsChannel}}"
      event="notifications:global"
      msg-latest="{{globalNotificationsState}}"
      counter="{{globalNotificationsUpdateCount}}"
      ></phoenix-channel-msg>
    <phoenix-channel-msg
      channel="{{notificationsChannel}}"
      event="notifications:direct"
      msg-latest="{{notificationsState}}"
      counter="{{notificationsUpdateCount}}"
      ></phoenix-channel-msg>
    <phoenix-channel-msg
      channel="{{notificationsChannel}}"
      event="dismiss"
      msg-send="{{dismissNotification}}"
      ></phoenix-channel-msg>

<!-- Snip some stuff for brevity -->


      <!-- Direct Notifications -->
      <template is="dom-repeat" items="[[notificationsState.notifications]]">
        <swipe-action
          data-notification-id$="[[item.id]]"
          class="item"
          tabindex$="[[tabIndex]]"
          on-swiped-away="_onSwipedAway"
          activated-action-id="[[_retFirst(0, notificationsUpdateCount)]]"
          >
          <paper-card
            notification-id="[[item.id]]"
            heading="[[item.title]]"
            image="[[_getBackgroundImageOfNotification(item)]]"
            placeholder-image="[[_genPlaceholderImage(item.color)]]"
            elevation="2"
            alt=""
            animated-shadow
            preload-image
            fade-image
            class="disable-selecting">
            <template is="dom-if" if="item.body">
              <div class="card-content">
                <template is="dom-if" if="item.icon">
                  <iron-icon icon$="[[item.icon]]"></iron-icon>
                </template>
                [[item.body]]
              </div>
            </template>
            <div class="card-actions">
              <paper-button notification-id="[[item.id]]" on-tap="_dismissNotification">Dismiss</paper-button>
              <span style="padding-left: 16px;">
                <time-ago datetime$="[[item.updated_at]]" format="micro-off">
                  [[item.updated_at]]
                </time-ago>
              </span>
            </div>
          </paper-card>

          <div swipe-left-action swipe-fade on-tap="onActionTapped" class="disable-selecting" style="color: gray" notification-id="[[item.id]]">
            Notification marked as read
          </div>
        </swipe-action>
      </template>
  </template>
  <script>
    Polymer({
      is: 'my-notifications',

    // Backing code, which is surprisingly short, only 3 real functions, one to handle a
    // button click, another to handle when a notification is swiped away, and a third that
    // generates base64 encoded image from some of the data from the server to
    // color-code notifications (I'm doing transforms on the image itself).  ^.^

    });
  </script>
</dom-module>

I can treat CSS like this is an isolated element, using direct selectors, I can pass CSS information (variables, entire blocks, etc…) up the tree via the mixins (the -- parts, I’m only passing information ‘up’ from this element but in others I also apply them too, this thing is only used in one place so I see no need to receive css here, so it is fully isolated). It is quite a pleasant way to write. :slight_smile:

Oh, and I use it in its parent element via:

          <my-notifications
            socket="{{socket}}"
            route="{{fullRoute}}"
            unread="{{unreadNotifications}}"
            notifications-state="{{notificationsState}}"
            style="padding-top: 64px"
          ></my-notifications>

So, yes, very nice to use. I just pass in the socket and route, get back an unread count and a notification state structure, the unread count appears on the notifications button and the state is applied to a global bottom-of-screen popup on an incoming notification as well as a web-notification popup if the user does not have the screen focused and they have it enabled (I could have done both of those ‘in’ my notification class, but I’m sharing the code with other things that occasionally cause toasts so it was easier just to pass the information back up as you see). :slight_smile:

Also, wtf is discourse doing with the color coding?!? It is set as html, so… wtf? o.O

1 Like

I looked into Web Components / Polymer over the weekend. Lots of interesting stuff: both one and two-way binding, shadow DOM, mixins, etc. You could even use Web-Components with React, if you were so inclined.

Just curious, from your code it looks like you are using Google’s Material Design. Are you heavily modifying it, or just using it as-is? One complaint I’ve heard is that you tend to end up with a “Google-branded” look-and-feel.

[sorry for wall of text, just a braindump of design stuff]

So you’ve hit the normal point in the design process where you’ve got too wide a scope and you get paralyzed. This is always going to be the case. I guess design is quite similar to programming in that it’s a method of dealing with complexity, and where you are is analogous to building a webapp, and starting by trying to do everything. When I was primarily a designer, the worst possible projects were always when a client said “just design me something”. The scope of any project is always enormous, and it takes a very long time to narrow it down. On the other hand, the jobs where the constraints were tight were the best to work on, and almost always led to the best designs, because I could focus immediately on the design. You need constraints, and helpfully, you’ve got one very, very useful constraint.

Start with your mobile version. It’s really restrictive, and as you say, there are well-established paradigms. Make it work on mobile viewport sizes, and make it work well. Then change the orientation, see what breaks. Fix that. Then go to tablet size. Do the same. Then go to desktop.

Things like navigation are really good to focus on first. At mobile, you don’t really want important nav items hidden away. So can you fit them all on one line? If not, maybe you want to use icons? Is this a good approach, will people understand what the icons mean. As the size increases, do you show more items? Where do you put the nav - would it be useful to have it at the bottom, so people can hit the items with their thumb, making it easier to use one handed? If you do that, what effect does it have on what you imagined for the rest of the design?

Focus on one thing you think is important and that you have an idea of how it should be implemented. Don’t be precious about it though, and build out stuff as fast as possible, and give it to someone to try.

The scope does extrapolate very quickly, but you need to grab hold of a a few small things at first, and work outwards from that. Try to pick the most important bit, but often you don’t realise quite what that is at first, so go for something you think you’ve got quite a solid idea of how it should function.

Work from functional to aesthetic - you can go the other way, but it makes the development side that bit harder.

Just keep polishing and polishing - it’s gets to be a grind as you go past the fun stuff and start to repeat yourself, but you get there in the end.

Don’t lose sight of the overall look and feel, it’s really easy to get trapped into polishing a single thing, so when you feel yourself stalling, move onto a different piece of functionality. Keep stopping and taking stock, zoom out so you can see the all the parts together - key aims is a fluid, unified experience, and it’s really easy to lose that and go down blind alleys.

One major thing I always find productive is find something you really like, aesthetically. Could be a colour combination, or a font you really like, or something very specific like a form input validation style you really think works. Focus on that, build it out - if it’s a font, get the spacing and weight looking really good on basic body text, then move onto headers, button text, etc. If it’s colours, try them with text, with backgrounds, with image overlays, different tints and shades for buttons, active states etc - note, this is where CSS frameworks are great; they’ll generally always have a Sass/Less version that you can set up the variables for. If it’s something more specific, then make that element work - really work, so tune the animations between states, maybe, until it it feels really fluid. Then make another element, say, a button, that follows the same pattern, maybe has the same colours and animation timings. And then the containers for the elements - echo the border styles, shadows, etc.


Re that last paragraph, this is book is great: https://www.amazon.co.uk/Visual-Grammar-Design-Briefs-Christian/dp/1568985819. There’s nothing particularly spectacular about it - it’s just a compendium of different strategies for laying out content displayed in a very simple, stark style. But it’s useful

This guy’s BA project is fantastic, covers a variety of animation strategies and the reasons for their use, I’ve used it as a go-to reference for years: http://www.ui-motion.com/#home

The designer Andy Rutledge’s archive articles here (all the ones under Practice) were very useful to me (note of warning, maybe ignore the Culture section unless slightly rabid US conservative politics are your bag. He’s a very good designer though).

Google’s Material Design documents are really good - whether you think it’s a good thing, or whether you think it’s awful, Matías Duarte et al thought very carefully about both individual elements and the overall scope. And that scope is massive, so it’s super impressive as a design system. The underlying design ideas are good - pinch at will.

There’s a book called ‘A Graphic Design Process from Start to Finish’ by Index Press which, although print-focussed, is a very nice overview of the full process, aimed at all levels of designer. It was a short run I think, so the copies on Amazon are a bit overpriced for what it is, but if you can find a cheap copy it’s definitely worth a look.

Here’s Bruce Tognazzi’s Principles of Interaction Design as well, it’s great: http://asktog.com/atc/principles-of-interaction-design/, though it’s going over the same ground as the books you mentioned.

10 Likes

Yeah, webcomponents are just a set of standards on HTML, they can be implemented via any method that you want, Polymer just uses the html5 standards of shadow dom and templates to make it very html’y, this is how most of my elements are implemented, or you can use pure vanillajs, which a couple of my elements are (relative time, phoenix stuff, etc…), or you can use react, which, oddly, was slower than polymer in my testing, it keeps re-rendering to its vdom and doing a lot of comparisons and such, where polymer uses html5 standard things, events for 2-way binding, only updating things that change and not only not touching but not even checking anything else for updates, etc…

Basically Polymer does this:

  • It uses the HTML5 <template> element for its templates, the template element is just an HTML5 element that does not render its children (in fact it does not even load its children in the DOM or as full elements, it is very basic and simple, and is fully supported in all browsers but IE, and even in IE it just ignores it thus rendering the children, but polymer sets template as “display:none;” so it never sees them either, just a touch slower since it loads it). Polymer then parses over the templates making them into a full DOM that can be cloned, setting up annotations in the registered parts of the template so it can setup 1-way or 2-way binding (described below).
  • It uses the shadow dom, but not really, it fakes the shadow dom in a somewhat limited (which I’ve never cared about the limits yet) way since the only browser that supports a shadow dom is Chrome so far (and it does use it natively in chrome since the shadow dom in the browser is faster than even a simple faked one in javascript). The shadow dom just makes the elements attached to the shadow dom root instead of the element not appear in the main document DOM (cannot be iterated over for example, they are 'internal). An example from the polymer docs follow, but the template in polymer is automatically loaded into the shadow dom root instead of the normal root. Once an element has a shadow dom root the browser will no longer display the user elements (the span’s in the my-el in the below example), though the user elements will show in the DOM still, but rather the shadow dom brings in via the <slot> elements the user elements, either all (when no name) or only the matching name (when name is specified). The advantage of this, other than not polluting the DOM with useless boilerplate (think a button ripple in material design), is your css in the shadow dom is protected from changes outside the shadow dom (which polymer emulates on non-shadow-dom browsers via adding generated class names appropriately, works really well). This means if your template has a ‘div’ for example then you could css match the ‘div’ instead of needing to make class names, simplifies the css, and no worry about things being mixed up. The user elements are styled via outside the shadow dom so no interaction there either. To pass CSS between elements inside and outside the shadow dom you have to use the CSS variables spec (supported by some browsers, polymer emulates it on the ones that are not), which are wonderfully easy to use (shown at the bottom of this example). The shadow dom style can apply styles to the user slots (via attributes like ::slotted and such), but outer css overrides it.
<!-- element template -->
<dom-module id="my-el">
  <template>
    ...
    <h2>
      <slot name="title"></slot>
    </h2>
    <div>
      <slot></slot>
    </div>
  </template>
</dom-module>

 ...
<!-- usage -->
<my-el>
  <span slot="title">Mr. Darcy</span>
  <span>Fun at parties.</span>
</my-el>


<!-- An example of using css variables to pass css into a shadow dom -->
<dom-module id="my-el">
  <template>
    <style>
      div {
        @apply --my-mixin; /* This takes the --my-mixin variable block and applies it entirely */

        background-color: var(--my-bg-color, "#FF00FF") /* apply a specified variable, with the optional default specified, otherwise this is not set */
      }
    </style>
    ...
  </template>
</dom-module>

<!-- Setting the css variables -->
<style>
my-el {
  --my-mixin { /* A block variable */
    color: blue;
    text-size: larger;
  };
  --my-bg-color: yellow; /* A value variable */
}
</style>
  • The HTML5 spec also defines “Observers”, such that you can new a new Observer and have it watch a javascript variable for changes, however most browsers do not support it, and Polymer does not even use it when it is available, rather Polymer (and other webcomponent style libraries) use events. So any time you set a top level variable in Polymer it automatically sends an event (since it controls the top level object and can see when something is set), for embedded things like objects inside objects you have to either use the set notation (like this.set("something.bloop.blah", theValue);) or you either have to set it then call this.notify("something.bloop.blah") (after setting the value like this.something.bloop.blah = theValue, notify is useful to batch changes too). You can also fire the custom event manually too. However it registers event handlers for the various variables that things want to know about and stops it from bubbling out unless you specify it to bubble out. It is quite efficient and this style is making WhatsWG think to just remove the Observer api altogether from the spec). However, this event system is what handles both the 1-way and 2-way data binding in Polymer. If you put [[someVar]] somewhere (or a path like [[something.bloop.blah]]) it will put the value there in the html, so doing something like <span>Time: [[theTime]]</span> will render the time as a string. You can have it call a function instead, passing in this variables too, like <span>Time: [[formatTime(theTime)]]</span> and it will call this.formatTime passing in this.theTime. It builds the dependencies from what is passed in, so it will only ever call formatTime when theTime changes via its internal events handling and registration. If a function access variables internally or you need to specify more dependencies then just specify them in the function call too. You can put this as properties on an object too, so doing <img src="[[imgPath]]"></img> will be, where the img element is ‘elem’ in this example, like doing elem.src = this.imgPath; any time this.imgPath changes. Do note, this is a property set, if it is an attribute you would need to do this instead <img src$="[[imgPath]]"></img>, just appending $ to the end of the attribute name, it will do elem.setAttribute('src', this.imgPath); instead anytime this.imgPath changes. This is rarely needed except for compat with raw html elements in ‘some’ cases (like the textbox ‘value’ attribute or so). Setting a variable in a property, attribute, or inline text is a 1-way data binding, it sets an update any time that value changed, nothing else, but say you have, for example, my phoenix element of <phoenix-channel socket="[[socket]]" channel="{{myChannel}}"></phoenix-channel>, the socket is a 1-way data binding, the phoenix-channel does not need to change its parent value of it after all, but channel is specified with curly brackets, thus it will propagate changes to the variables into the element, but also allow the element to send changes out (internally it broadcasts it wants to change it via an event). You can use curly brackets any place that you use square brackets in 1-way binding and it falls back to 1-way binding if it is not an acceptable 2-way binding location, so in almost every case you can just make everything with {{}} instead of [[]] anyway unless you really want to prevent an element from changing the variable. In addition polymer lets you do on-<eventname> to call a callback when an element propagates an event up, such as with <div on-click="myCallback">...</div> will call this.myCallback(event) anytime that div is clicked. Do note that onclick is the html name for the event there, Polymer registration is via on-click or on-whatever-event, and you can fire an even yourself via normal html event firing ways (or via a helper this.fire("event-name", eventData); if you want).
  • If you notice, the above is entirely usable via anything else really, you can mount a, for example, Elm app as an element, listen to events from within elm to listen for 2-way binding changes, set properties or attributes inside elm, all with normal elm code. The only thing you cannot do from within elm to be a webcomponent is listen for property changes on yourself (elm really needs a new subscription for that, easily done, but requires elm native code), and it is even easier in React or about any other too. Most of my webcomponents are polymer based, some are vanilla JS, one is elm, one is bucklescript, it works well everywhere and lets you compose up your elements just as normal html.

Polymer gives you lots of injection points to change up the theme, and as such our site has been themed to fit our color and style scheme (the old method was bootstrap’y), you can barely tell it is material except for the shadows, drawer, and ripples, and even all of those have been re-themed for our style (with very little css surprisingly). And it works significantly better on mobile than the old bootstrap setup as well, but that was mostly because the old designers did not know how to use bootstrap properly.

2 Likes

Well, I recently got very very interested in trying a little bit the Bourbon suite. It seems dauting because it’s almost starting from scratch, but I really had a lot of pain trying to fit bootstrap, foundation and other frameworks to my needs, that I really consider doing it, and bourbon seems like a lot less intrusive.

Did anyone tried it?

I mention Bourbon in this thread and I keep meaning to try it - it certainly seems like a great way to go about things :slight_smile:

1 Like

@DanCouper This is the reply that I started this topic for! Thank you very much. I will look into your recommendations and come back.

1 Like