diff --git a/docs/README.md b/docs/README.md index 74c656d6..40e8de06 100644 --- a/docs/README.md +++ b/docs/README.md @@ -51,7 +51,7 @@ Documentation for specific topics can be found in the following files: * [Customization checklist](customization-checklist.md) * [Google Maps](google-maps.md) * [i18n](i18n.md) -* [Icons](colors-and-icons.md) +* [Icons](icons.md) The application was bootstrapped with a forked version of [create-react-app](https://github.com/facebookincubator/create-react-app). While most of the diff --git a/docs/assets/styling/styling-find-component.png b/docs/assets/styling/styling-find-component.png new file mode 100644 index 00000000..0760ee38 Binary files /dev/null and b/docs/assets/styling/styling-find-component.png differ diff --git a/docs/customization-checklist.md b/docs/customization-checklist.md index deeeb9bd..775a2f9f 100644 --- a/docs/customization-checklist.md +++ b/docs/customization-checklist.md @@ -2,8 +2,8 @@ Some generic things to update and check when starting to customise the template. -* [Marketplace colors](colors-and-icons.md#colors) -* [Generate app icons](colors-and-icons.md#icons) +* [Marketplace colors](styling.md) +* [Generate app icons](icons.md) * [Update translations](../src/translations/en.json) or [change the language](i18n.md) * [LandingPage](../src/containers/LandingPage/LandingPage.js): update and create branded sections * [Footer](../src/components/Footer/Footer.js) diff --git a/docs/styling.md b/docs/styling.md new file mode 100644 index 00000000..39be804c --- /dev/null +++ b/docs/styling.md @@ -0,0 +1,275 @@ +# Flex Template for Web: styling + +The goal for creating styling for Flex template app was to keep styling as close as possible to +plain CSS writing while still trying to avoid the mess that comes along with globally defined +cascading behavior that CSS is all about. + +To tackle this goal, we have split the styling into two levels in this template application: + +* [Marketplace level styling](#marketplace-level-styling) through _marketplace.css_ (a kind of + global theme) +* [Component level styling](#styling-components) using + [CSS Modules](https://github.com/css-modules/css-modules) + +## Marketplace level styling + +On top of functionalities provided by Create React App, we have +[added a couple of extra libraries](https://www.npmjs.com/package/sharetribe-scripts#differences-to-react-scripts) +to help to design consistent UIs faster. CSS Properties and CSS Property Sets are very useful for +all kind of style sharing purposes, and we have created marketplace-level styling variables with +them. + +The concept behind CSS Properties is quite straightforward - they are variables that can be defined +in root-element level and then used inside some CSS rule. + +```css +:root { + --marketplaceColor: #ffff00; +} + +.linkToHomePage { + color: var(--marketplaceColor); +} +``` + +(Read more about CSS Properties from [cssnext](http://cssnext.io/)) + +We have used this concept to create a marketplace-level "theming" that's defined in three files: +_src/marketplace.css_, _src/marketplaceFonts.css_, and _marketplaceIndex.css_. + +### marketplace.css + +This is a good place to start customizing marketplace styles. For example, we define our color +scheme here using CSS Property variables: + +```css +/* ================ Colors ================ */ + +--marketplaceColor: #c0392b; +--marketplaceColorLight: #ff4c38; +--marketplaceColorDark: #8c291e; + +/* Used with inline CSS SVGs */ +--marketplaceColorEncoded: %23c0392b; + +--successColor: #2ecc71; +--successColorDark: #239954; +--failColor: #ff0000; +--attentionColor: #ffaa00; + +--matterColorDark: #000000; +--matterColor: #4a4a4a; +--matterColorAnti: #b2b2b2; +--matterColorNegative: #e7e7e7; +--matterColorBright: #fcfcfc; +--matterColorLight: #ffffff; +``` + +Changing `--marketplaceColor: #c0392b;` to `--marketplaceColor: tomato;` will change the default +marketplace color to tomato color. (It's a certain kind of red color.) + +The `--marketplaceColorEncoded` variable holds the same value as `--marketplaceColor` but with the +_#_ URL encoded. This value can be used to maintain a consistent color scheme with inline SVG icons. + +`--successColor` (green) is used on form inputs for showing that the input value is valid. +Sometimes, submit buttons (``) are also using that color to highlight the fact that +user has entered valid information to the form at hand. + +Similarly `--failColor` is used to style errors and `--attentionColor` is used to draw user's +attention to certain UI components (e.g. required form inputs, or important info in Inbox) + +Our greyscale colors (for borders and background colors) are named with prefix _"matter"_. + +Similar pattern is also used to create more consistent UI components by providing variables for +box-shadows, border-radiuses, transitions, and so on. Our current plan is to parameterize styling +even more using this concept. + +Breakpoints for media queries are also defined in this file: + +```css +/* ================ Custom media queries ================ */ + +@custom-media --viewportMedium (min-width: 768px); +@custom-media --viewportLarge (min-width: 1024px); +@custom-media --viewportXLarge (min-width: 1921px); +``` + +### marketplaceFonts.css + +Fonts are specified in this files using CSS Property Sets. They provide us a solid way of creating a +fixed set of CSS rules for a specific font. + +For example, our default font is defined as: + +```css +--fontWeightMedium: 500; + +--marketplaceDefaultFontStyles: { + font-family: 'sofiapro', Helvetica, Arial, sans-serif; + font-weight: var(--fontWeightMedium); + font-size: 18px; + line-height: 24px; + letter-spacing: -0.1px; + + @media (--viewportMedium) { + font-size: 20px; + line-height: 24px; + } +} +``` + +And created property set can be used as: + +```css +p { + @apply --marketplaceDefaultFontStyles; +} +``` + +_marketplaceFonts.css_ are included to _marketplace.css_, so you don't need to import this file on +new components (importing _marketplace.css_ is enough). + +⚠️ NOTE: template app is following a pattern where the height of an element should be divisible by +`6px` on mobile layout and `8px` on bigger layouts. This affects to line-heights of font styles too. + +⚠️ NOTE: the `@apply` rule and custom property sets most likely won't get any more support from +browser vendors as the spec is yet considered deprecated and alternative solutions are being +discussed. However, template app will use these until a good enough alternative is available. + +### marketplaceIndex.css + +This file provides default styles for plain elements like ``, ``, `

`, ``, `

`, +`

`, and so on. + +## Styling components + +Styling a web UI is traditionally quite a messy business due to global nature of stylesheets and +especially their cascading specificity rule. `.card {/*...*/}` will affect every element on a web +page that has a class `card` - even if the different UI context would like to use a different set of +rules. + +Our goal has been to create independent components that can be reused in the UI without paying too +much attention to the global CSS context. To achieve this, we have used +[CSS Modules](https://github.com/css-modules/css-modules), which keeps the syntax close to plain +CSS, but it actually creates unique class names to remove the problems caused by the global nature +of CSS. In practice, this means that a class with name `card` is actually renamed as +`ComponentName__card__3kj4h5`. + +To use styles defined in SectionHero.css, we need to import the .css file into the component: + +```jsx +import css from './SectionHero.css'; +``` + +and then select the correct class from imported style object (in this case `heroMainTitle`): + +```jsx +

Book saunas everywhere

+``` + +### Find the component to change its styles + +Quite often one needs to find a component that is responsible for certain UI partial in order to +change the styles. In this case, the easiest way to pinpoint a component is to open the inspector +from browser's dev tools. (Right-click on top of the correct element, and select _Inspector_, or +something of the sort depending on the browser, from the context menu.) + +![Mobile LandingPage hero title](./assets/styling/styling-find-component.png) + +Here we have opened title on LandingPage and the styles for +`

Book saunas everywhere.

` are +defined in a "class" called `SectionHero__heroMainTitle__3mVNg`. As stated before, the first part of +a class name is actually giving us a hint about what component is defining that style - in this +case, it's _SectionHero_ and its styles can be found from the file: +`src/components/SectionHero/SectionHero.css`. + +There's only two groups of components that break that rule: + +* _src/containers_ (These components are connected to Redux store: Pages and TopbarContainer) +* _src/forms_ + +### Styling guidelines and good practices + +We have a practice of naming the outermost class of a component as `.root { /* styles */ }`. So, if +the component is just rendering single element it only has `.root` class, and if there's more +complex inner DOM structure needed, additional classes are named semantically. + +`` could contain classes named as `.root`, `.heroMainTitle`, `.heroSubtitle`. + +Some guidelines we have tried to follow: + +* **Use semantic class names** (They improve readability and decouples style changes from DOM + changes.) +* **Use CSS Properties defined in marketplace.css** and create new ones when it makes sense. +* **Use classes**, don't style DOM elements directly. (Element styles are global even with CSS + Modules.) +* **Avoid nesting styles**. (CSS Modules makes specificity rules unnecessary.) +* **Group and comment style rules** inside declaration block if that improves readability. +* **Parent component is responsible for allocating space** for a child component (i.e. dimensions + and margins). +* **Define `@apply` rules early enough** inside declaration block (since rules inside those property + sets might overwrite rules written above the line where the set is applied). +* **Align text and components** to horizontal baselines. I.e. they should be a multiple of `6px` on + mobile layout and `8px` on bigger screens. +* **Component height should follow baselines too**. I.e. they should be a multiple of `6px` on + mobile layout and `8px` on bigger screens. _(Unfortunately, we haven't been strict with this + one.)_ + +### Styling responsibility: parent component and its children + +One important aspect of a component-based UI is the fact that a component is usually only +responsible for what happens inside its outermost element boundary. In parent-child context this +means that the parent component is responsible for its own layout and therefore it usually needs to +be able to give some dimensions to its child components (and naturally margins between them). + +This creates a need for the parent to have means to pass `className` to its child as props. One +example could be a component that shows a circle component inside itself and makes it 50px wide. + +Style definitions of the (``) child component: + +```css +.root { + backgroundcolor: tomato; + border-radius: 50%; +} +``` + +Parent component renders +(`
`): + +```css +.root { + min-width: 60px; + min-height: 60px; + display: flex; + align-items: center; + justify-content: center; +} + +.circleDimensions { + flex-grow: 0; + width: 50px; + height: 50px; + margin: 5px; +} +``` + +Sometimes the child component needs to be styled even further than just allocating space to it. If +the parent component wants to change the theme of child component there are generally two concepts +available: + +* Create themed components (e.g. ``, ``, ``) +* Pass in a `class` property that is able to overwrite original styling rules. + +For the latter option, we have created a prop type concept called `rootClassName`. If you pass +`rootClassName` through props to a component, it will use that instead of component's own style +rules defined in `.root`. This ensures that the order of style declarations inside final CSS bundle +doesn't affect the final styles. (CSS bundle is generated in an import order, therefore we want to +avoid situations where `` could end up overwriting each others +depending on the order they are imported.) + +In some complex cases, we have also created props for overwriting some inner classes of child +components. In these cases, child component is also replacing its own styling class with the class +passed-in through props. For example, `` can take a prop called +`iconClassName`, which (if given) replaces `.icon` class defined inside +`LocationAutocompleteInput.css`. diff --git a/docs/colors-and-icons.md b/icons.md similarity index 78% rename from docs/colors-and-icons.md rename to icons.md index 7133e5be..59fcbcf6 100644 --- a/docs/colors-and-icons.md +++ b/icons.md @@ -1,28 +1,4 @@ -# Colors and icons - -One of the first customisations is to change the marketplace colors and icons. - -## Colors - -To change the marketplace colors, open the [src/marketplace.css](../src/marketplace.css) file and -change the color variables: - -```css ---marketplaceColor: #c0392b; ---marketplaceColorLight: #ff4c38; ---marketplaceColorDark: #8c291e; -``` - -and - -```css ---marketplaceColorEncoded: %23c0392b; -``` - -N.B. search also from files for the color code `c0392b`. It's used directly in a few places like -some icons, the 500 error page and map configurations. - -## Icons +# Icons The default icons are generated with [RealFaviconGenerator](https://realfavicongenerator.net/). You can upload your original icon to the tool, customise the colors and themes, and download a generated diff --git a/src/marketplace.css b/src/marketplace.css index 49e6dd62..b238c708 100644 --- a/src/marketplace.css +++ b/src/marketplace.css @@ -46,6 +46,9 @@ --marketplaceColorLight: #ff4c38; --marketplaceColorDark: #8c291e; + /* Used with inline CSS SVGs */ + --marketplaceColorEncoded: %23c0392b; + --successColor: #2ecc71; --successColorDark: #239954; --failColor: #ff0000; @@ -60,9 +63,6 @@ --matterColorLightTransparent: rgba(255, 255, 255, 0.65); - /* Used with inline CSS SVGs */ - --marketplaceColorEncoded: %23c0392b; - /* ================ Spacing unites ================ */ /* Multiples of mobile and desktop spacing units should be used with margins and paddings. */