demo-chat-scroll

A step by step guide to front-end development using a simple chat as example.


https://stackoverflow.com/questions/57367962/chat-does-not-scroll-to-the-bottom-when-i-use-jquery-load-method

Back to index

Before jumping in and give the implementation in jQuery, let’s take a step back and implement this in a framework/library agnostic way. That can then, be either augmented or refactored to use a library, like jQuery, or a framework like Vue.js.

We are going to look at best practice for front-end architecture, Cascading Style Sheets (CSS) naming conventions and the most common used Document Object Model (DOM) APIs.

Architecture

The most used front-end architecture is Model View Controller (MVC) or small deviations of MVC. That means that our chat app has decoupled code that manages how and where we get our data (Model), what a user can see - presentation of our data (View) and the code that controls the Model and react to user actions (Controller).

As shown above; the Model never speaks to the View and vice versa.

View

A front-end View, mainly, consist of HTML and CSS. HTML is pretty easy to grasp which is also the whole point of HTML. However, we do strive for semantic HTML. That is, HTML that convey a meaning about the structure. This is both helpful for the next developer, who need to read your code, for search engines and screen readers.

For our simple chat we will use the following HTML:

<section class="chat chat--disabled">
  <div class="chat__output">
    <p class="chat__message">message 1</p>
    <p class="chat__message">message 2</p>
    ...
  </div>
  <button class="chat__toggle">Enable</button>
</section>

<section> denote a block that can be reused on the same page or across pages. <p> is a paragraph of text, in this case a chat message. <button> conveys an action to enable/disable the chat module. <div> has no semantic meaning but we will use the element to measure scrolling position and add new <p> elements.

CSS

More often than not, we need to create elements for styling purposes. While you should know ::before and ::after, which can be used to create hidden pseudo elements for styling purposes. It’s often necessary to create one or two elements for the sole purpose of styling and/or programmatically measure/manipulate. In the case that an element has no semantic meaning, we use <div> for block elements and <span> for inline elements. If an element has a semantic meaning, you should search for another element to convey the meaning of your structure.

You probably also noticed that each HTML element in our chat has a class attribute and their naming is somewhat consistent. What I have used here is Block Element Modifier (BEM), which guarantees that CSS does not cascade out of our chat module to other parts of our app, as long as the Block name is unique (it’s conflict free). This technique works well for both small and big apps and is heavily optimized in all browsers as oppose to CSSinJS which has a negative impact on performance and is more difficult to setup, whereas a naming convention has zero setup (except for the setup happening in your brain).

The structure of BEM is:

  1. Block - The root element of your module.
  2. Element - The elements inside your module.
  3. Modifier - Changes to your block or your elements.

For our little example we will use the following CSS:

.chat {}

.chat__output {
  height: 80px;

  overflow-y: scroll;

  transition: background-color 250ms;
}

.chat--disabled .chat__output {
  background-color: hsla(0, 0%, 0%, 0.4);
}

.chat--enabled .chat__output {
  background-color: hsla(0, 0%, 0%, 0);
}

.chat__message {
  margin: 0;
  padding: 0 .2em;

  line-height: 1.4em;
}

.chat__message:nth-child(odd) {
  background-color: hsla(0, 0%, 0%, 0.2);
}

Not all HTML elements in a block has to be a BEM element and we don’t absolutely have to style every BEM element, but experience tells me that in a real world scenario, we probably will style every BEM element. We have 2 states, enabled/disabled (chat--enabled/chat--disabled), which we visualize with a fading transition of the background color. Our .chat__message is currently a <p> element, which is a block element in CSS terms (not BEM) and has some browser styling by default. We negate the default margin and add a little spacing for readability. You should use a CSS normalize base for any app that has considerable styling. A good one is normalize.css.

The key points of BEM performance is:

  1. Standalone CSS selectors. Except for state modifiers.
  2. Parallelism, since styles are static.
  3. Non-competing with the main thread since, since styles are static and not applied via js.
  4. [Scalable/Distributed, since styles are not generated on a server][cssServerSide].

If the above has not convinced you, then we can take a lengthy talk about it in another forum. I think it’s an emotional topic and we should really move on to talk about the Model.

Model

JavaScript (js) is a multi-paradigm language. As such we can write our program in FP, OOP (class/class-less), AOP and imperative style. Aside from imperative style, I think class based OOP, known from Java, C#, PHP, etc, is the most known and widely used paradigm, so our first implementation will use class based OOP, written in close to PHP style.

First we need to define our model. We are going to use simple and well understood patterns. This is not necessary the most efficient or elegant implementation but should be easy to grok.

[cssServerSide]: https://cssinjs.org/server-side-rendering?v=v10.0.0-alpha.24 “Since a browsers do work on a user’s machine, it does not matter if you have 1 or 1.000.000 simultaneous users, but if you move the same work to your server, it DOES matter, if you have to do the same work 1 or 1.000.000 times!”