Counteract a bootstrap / select2 rendering delay?
Asked Answered
G

5

10

I'm using bootstrap on a site, and using the following code on load to turn my select boxes into select2 dropdowns

$("select").select2();

However when any page with a select dropdown loads, there's a brief delay where the original can be seen before the select2 replacement is drawn in. This is quite jarring as elements of the forms on my pages move around.

Is there a way to generate the select2 HTML in my backend (ASP MVC3) and write it out to the page in such a way that the select2 plugin will still hook up all the behaviours correctly?

Glimp answered 24/4, 2015 at 14:8 Comment(2)
That's odd, as I use the same control and don't get any FOUC...but I also have the select 2 styled much like the .form-control class, so I wouldn't get any jumping of elements. As an option, look into ways of dealing with FOUC. I wish I had better advice, hopefully someone smarter than me will be able to help out.Outdate
possible duplicate of Bootstrap-select plugin: how to avoid flickeringAlderson
G
5

I went for a slighly simpler answer. All form elements now have style='display:none;'. On page load I simply do $('form').show()

This is at the end of any select2 commands, so the form only appears when everything else has been rendered.

In the case of lazy loaded table rows with checkboxes, I set style='display:none;' on the checkboxes and then have them show when loading is finished for a particular 'page' of results.

Glimp answered 14/5, 2015 at 11:37 Comment(0)
A
3

Here's a similar question on preventing flickering with Bootstrap-Select.

The fact is that a Flash of Unstyled Content (FOUC) is going to happen anytime that JavaScript is running on the client after the page has rendered and changes the appearance of the page. You're best bet is to just minimize the changes ahead of time.

The heavy handed approach would be to wait to display the page until all the scripts have run, but this is much worse for users.

As Roryok suggested, the best way to mitigate this issue is to style the appearance of the native element as close as possible to the plugin control.

To do that, just add the following css to any select element which will be applied before the javascript renders the control.

/* apply styles to original select element before hidden */
select.select2{
  color: #444;
  background-color: #FFF;
  border: 1px solid #AAA;
  border-radius: 4px;
  box-sizing: border-box;
  cursor: pointer;
  display: block;
  height: 28px;
  padding-left: 5px;
  font: unset;
}

Demo in Stack Snippets

$('.select2').select2();
body {
  display: flex;
  flex-direction: row;
}

div {
  padding: 15px;
  display: flex;
  flex-direction: column;
}

label {
  font-weight: bold;
}

select {
  min-width: 150px;
}

.select2-theme {
  color: #444;
  background-color: #FFF;
  border: 1px solid #AAA;
  border-radius: 4px;
  box-sizing: border-box;
  cursor: pointer;
  display: block;
  height: 28px;
  padding-left: 5px;
  font: unset;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.7/css/select2.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.7/js/select2.js"></script>


<div >
  <label>Select 2</label>
  <select class="select2">
    <option>Mustard</option>
    <option>Ketchup</option>
    <option>Relish</option>
  </select>

</div>

<div>
  <label>Select2 Themed</label>
  <select class="select2-theme">
    <option>Mustard</option>
    <option>Ketchup</option>
    <option>Relish</option>
  </select>
</div>

<div>
  <label>Default Select</label>
  <select >
    <option>Mustard</option>
    <option>Ketchup</option>
    <option>Relish</option>
  </select>  
</div>
Alderson answered 24/4, 2015 at 14:48 Comment(3)
The problem with this is that the select can't be styled in every browser AFAIK. I think I might just fake the generated HTML as a placeholder and then drop it out when select2 fires. Maybe I can use absolute positioning to layer the actual select2 over the fake select2 HTMLGlimp
I like this, and it sort of works. Is less jarring. But wonder if it could go one better and copy the select2 font as well. The box is well copied, the contents aren't.Universe
@BerndWechner, updated the example. Select2 itself doesn't change the font family, but the user agent stylesheet actually has different CSS font properties for selects vs spans so I added the value to unset so it would return to the browser defaultAlderson
I
2

Per @roryok's answer, CSS is rendered first so the best solution is to hide the form until after select2 loads.

However you should use visibility:hidden; rather than display:none; so Select2 can access the form input width when rendering its own DOM additons.

Irmgard answered 14/2, 2020 at 11:8 Comment(1)
This worked best for meCake
S
1
select.select2{display: none}

Works for me (at least in a horizontal form). It simply hides the search box until search2 has rendered it.

Sergu answered 3/12, 2019 at 8:7 Comment(3)
That would stop the select from displaying at all.Irmgard
No, it stops it displaying until javascript renders the replacement elementsSergu
In that case you need to clarify you are referring to CSS and you would need select.#my_id{display: none !important}. It helps with FOUC but not with placeholder height.Irmgard
F
1

The best and most simple answer:

Add the existing Bootstrap class invisible to your Select2 object on the markup page, whether it's an ASP:DropDownList, HTML Input element, HTML Select element, etc: https://getbootstrap.com/docs/5.2/utilities/visibility/

This prevents the HTML version of the Select/DDL from being visible to the user, while reserving the space in the layout that the SELECT would take up (which is rendered in once the Select2 JS is initialized).

Fourierism answered 6/12, 2021 at 18:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.