How to Selectively Hide or Display Elements Based on the Web Browser Using CSS


I recently encountered a situation in which a feature I wanted to add to my website was not supported in Internet Explorer because it relied on third-party JavaScript code that is not supported in Internet Explorer. The feature was trigged by pressing a button. The page was displayed properly but when the button was pressed nothing happened. The console revealed the reason why nothing happened when the button was pressed. The third-party JavaScript code uses a language feature not supported by Internet Explorer.

I decided that the simplest solution was to hide the button for Internet Explorer and display it for all other web browsers.

A quick Google search suggested that this was easy. The article How To Create an IE-Only Stylesheet suggested that all I need to do is use conditional comments as follows.


<!--[if !IE]><!-->
<p>This paragraph should be hidden in Internet Explorer and visible in all other web browsers.</p.
<!--<![endif]-->

While this does work for older versions of Internet Explorer, it does not work for Internet Explorer 10 and Internet Explorer 11 as discussed in Conditional comments are no longer supported.

After giving this some thought, I decided that it might be possible to do this using CSS, as follows.


if (IsInternerExplorer()) {
.hidden-for-ie-visible-for-others {
    display:none !important;
}
else {
.hidden-for-ie-visible-for-others {
    display:block;
}
}

The problem is that CSS does not support if/else statements.

The Quest for a Solution

I found several good resources such as How to Target Internet Explorer 10 and 11 in CSS that showed how to do the if part. It can be done as follows.


@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.hidden-for-ie-visible-for-others {
    display:none !important;
}
}

Unfortunately, the How to Target Internet Explorer 10 and 11 in CSS does not provide any information on how to do the else part. I was at a loss for how to do the else part until I thought to do a Google searc for css not Internet Explorer. This led me to the StackOverflow question Apply CSS to all browsers except IE using media query. The accepted answer suggests that the @supports rule can be used to detect all browsers except Internet Explorer as follows.


@supports not (-ms-high-contrast: none) {
   /* Non-IE styles here */
}

Unfortunately, -ms-high-contrast is not supported for older versions of Internet Explorer; it was added in Internet Explorer 10. Therefore, if we were to make use of both the @media technique and the @supports technique the hidden-for-ie-visible-for-others class would be defined for Interner Explorer 10 and Internet Explorer 11 and for most other browsers but it would not be defined for older versions of Internet Explorer.

The Solution

Fortunately, the CSS Specificity feature provides a solution. CSS properties are calculated using Precedence Rules. A simple description of these Precedence Rules is as follows.

  1. Inline css (html style attribute) overrides css rules in style tag and css file.
  2. A more specific selector takes precedence over a less specific one.
  3. Rules that appear later in the code override earlier rules if both have the same specificity.
  4. A css rule with !important always takes precedence.

Source: What is the order of precedence for CSS?

Therefore, the hidden-for-ie-visible-for-others class can be defined as follows.


/* Define the hidden-for-ie-visible-for-others class for old
versions of Interner Explorer. */
.hidden-for-ie-visible-for-others {
    display:none;
}
/* Define the hidden-for-ie-visible-for-others class for
Interner Explorer 10 and Interner Explorer 11. */
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.hidden-for-ie-visible-for-others {
    display:none !important;
}
}
/* Define the hidden-for-ie-visible-for-others class for
other modern browsers. */
@supports not (-ms-high-contrast: none) {
.hidden-for-ie-visible-for-others {
    display:block !important;
}
}

Then you can use the hidden-for-ie-visible-for-others class as follows.


<p class="hidden-for-ie-visible-for-others">This paragraph should be hidden in Internet Explorer and visible in all other web browsers.</p.

Advertisements

The Birth of the Trump Economy

The Trump Economy
The Trump Economy

Economies are truly enormous. They are so large that as a result of the law of conservation of momentum, they take forever to stop, speed up, slow down, or change direction. For this reason, the Obama economy is just now coming to an end.

The Trump economy is a new born baby, and it does not appear to be healthy.

Trump is well aware of this. Why else would he have had his official propaganda machine, the West Wing Reads mailing list, send out the following drivel this morning?

Americans’ View of the Current Economy is the Highest in 19 Years

Americans’ assessment of current economic conditions has climbed to the highest level in nearly two decades, buoyed by a strong job market, Reade Pickert reports for Bloomberg.

He is desperately trying to distract us from the truth by shouting as loud as he can, the economy is doing great.

Perhaps Democrats should just let the Trump economy grow up; Let Donnie Trumplestiltskin commit political suicide, then offer salvation.


All hail Donald Trump; a.k.a. Donald Drumpf, a.k.a. Lord Dampnut, a.k.a. Dumbnut, a.k.a. Donnie Trumpelstiltskin, a.k.a. Donald tRUMP; our most, or perhaps least, honored (not my) POTUS and our great Bloviator in Chief!


The Trump Economy Image Information

Source
Wikimedia Commons: Baby Trump blimp
License
Creative Commons Attribution-Share Alike 4.0 International license

Using a select element to change the active stylesheet for a web page.

This article discusses the use of a select element to change the active stylesheet for a web page. It also provides step by step instructions on how to create the select element.

  • Add a link element to the head of your web page. Set the rel attribute to “stylesheet,” the href attribute to the URL of the default stylesheet you wish to use for your web page, and the id attribute to a unique value.

    Code Example:

    <link
      rel="stylesheet"
      href="https://www.w3.org/StyleSheets/Core/Swiss"
      id="W3C-Core-Styles" />
    

  • Add the select element. Set the value attribue of each option element to the URL of the stylesheet and the contents of each option element to the text you wish to be displayed for the combo box.

    Code Example:

    <select id="SeclectW3CCoreStyle">
    <option
      value="https://www.w3.org/StyleSheets/Core/Chocolate">
    Chocolate
    </option>
    <option
      value="https://www.w3.org/StyleSheets/Core/Midnight">
    Midnight
    </option>
    <option
      value="https://www.w3.org/StyleSheets/Core/Modernist">
    Modernist
    </option>
    <option
      value="https://www.w3.org/StyleSheets/Core/Oldstyle">
    Oldstyle
    </option>
    <option
      value="https://www.w3.org/StyleSheets/Core/Steely">
    Steely
    </option>
    <option
      value="https://www.w3.org/StyleSheets/Core/Swiss">
    Swiss
    </option>
    <option
      value="https://www.w3.org/StyleSheets/Core/Traditional">
    Traditional
    </option>
    <option
      value="https://www.w3.org/StyleSheets/Core/Ultramarine">
    Ultramarine
    </option>
    </select>
    

    Typically, I add this select element, along with a lable and the Set Style button, to the footer at the bottom of the page.

  • Add a Set Style button, as follows.

    Code Example:

    <input
      id="SetW3CCoreStyleButton"
      onclick="SetStyle('SeclectW3CCoreStyle', 'W3C-Core-Styles')"
      type="button"
      value="Set Style" />
    

  • Add the following JavaScript code to a script element in your page or to a .js file on your website.

    function isEmptyOrSpaces(str){
      if (str == null){
        return true;
      }
      if (str.length == 0){
        return true;
      }
      if (str.trim() === ''){
        return true;
      }
      return false;
    }
    
    function SetStyle(selectStyleElementId, linkElementId){
      console.log(
        "SetStyle('" + selectStyleElementId
        + "', '" + linkElementId
        + "') called.");
      let seclectStyleElement =  document.getElementById
        selectStyleElementId);
      if (!seclectStyleElement){
        console.log(
          "Could not find the '" + selectStyleElementId
          + "' element.");
        return false;
      }
      let seclectedStyle = seclectStyleElement.value;
      if (isEmptyOrSpaces(seclectedStyle)){
        console.log("Could not get the selected style.");
        return false;
      }
      let linkElement = document.getElementById(linkElementId);
      if (!linkElement){
        console.log(
          "Could not find the '" + linkElementId
          + "' element.");
        return false;
      }
      linkElement.setAttribute("href", seclectedStyle);
      return true;
    }
    

This example is fully functional. It does lack one key feature, the ability to store the selected style in a cookie. The article Store and Retrieve Cookies demonstrates the use of the localStorage.setItem and localStorage.getItem functions.

Modify the SetStyle function by adding the folloing line just above the ‘return true;’ line at the bottom of the function.


window.localStorage.setItem(
  "SeclectedStyle", seclectedStyle);

Note that the localStorage object is only supported on modern web browsers. That said, the Local storage with Window.localStorage page provides JavaScript code to emulate the feature for older browsers.

The next step is to set the style and the selected item in the select element when the web page loads. To acomplish this you need to add the following function.


function SetStyleFromCookie(selectStyleElementId, linkElementId){
  console.log(
    "SetStyleFromCookie('" + selectStyleElementId + "', '" + linkElementId + "') called.");
  let seclectedStyle = window.localStorage.getItem(
    "SeclectedStyle");
  if (isEmptyOrSpaces(seclectedStyle)){
    console.log(
      "Failed to get the value of the 'SeclectedStyle' cookie. Using the default value.");
    seclectedStyle = 'https://www.w3.org/StyleSheets/Core/Swiss';
  }
  let linkElement = document.getElementById(linkElementId);
  if (!linkElement){
    console.log("Could not find the '" + linkElementId + "' element.");
    return false;
  }
  linkElement.setAttribute("href", seclectedStyle);
  let seclectStyleElement =  document.getElementById(selectStyleElementId);
  if (!seclectStyleElement){
    console.log("Could not find the '" + selectStyleElementId + "' element.");
    return false;
  }
  seclectStyleElement.value = seclectedStyle;
  return true;
}

Finally, use the following code to call the SetStyleFromCookie function when the web page is loaded.


window.addEventListener('DOMContentLoaded', (event) => {
  SetStyleFromCookie('SeclectW3CCoreStyle', 'W3C-Core-Styles');
});

References

To see this code in action, go to Using a select element to change the active stylesheet for a web page.

The Undeniable Truth About the Crisis at the Border

One thing that has not been discussed enough is that the current immigration crisis was created by the United States. The United States has been taking actions that have destabilized Central America for the past 100 years.

In addition, the migrants have been mischaracterized by the Republican party as illegal immigrants. They are not. The asylum laws say you have to come here to the United States before you can ask for asylum. There is no possible way of asking for asylum while outside of the United States.

I know what some of you are no doubt saying right now; “you are supposed to seek asylum at a border crossing.” That is exactly what they are trying to do.

Asylum seekers are being turned away at the border, and have been all along. The actions of the Trump administration is in violation of international law.

These legal seekers of asylum are being forced to wait at the border for weeks or even months in a dangerous situation until they have no choice to cross the border without permission in the hopes that they can try to request asylum again once they have crossed the border.

So lets review.

  1. The United States has spent 100 years destabilizing Central America.
  2. Things have finally become so bad in Central America that people are fleeing to seek a better life elsewhere.
  3. You cannot request asylum until you are here in the United States.
  4. When the legal asylum seekers arrive at the border they are being turned away illegally.
  5. These legal asylum seekers are left with no choice but the cross the border without permission since they are being turned away illegally at border crossings so they can try to request asylum again once they are here.

If the Democrats want to force Trump out of office, they need to focus on making these truths known to all.


All hail Donald Trump; a.k.a. Donald Drumpf, a.k.a. Lord Dampnut, a.k.a. Dumbnut, a.k.a. Donnie Trumpelstiltskin, a.k.a. Donald tRUMP; our most, or perhaps least, honored (not my) POTUS and our great Bloviator in Chief!


Providing Accessibility Information in a .NET Windows Forms application

Windows Forms applications provide two mechanisms for providing accessibility information.

In many cases the required accessibility information can be provided using the following properties of the Control Class in the System.Windows.Forms Namespace: the Control.AccessibleDefaultActionDescription Property, the Control.AccessibleDescription Property, the Control.AccessibleName Property, and the Control.AccessibleRole Property. This feature is almost enough to meet WCAG Success Criterion 4.1.2: Name, Role, Value. WCAG Success Criterion 4.1.2: Name, Role, Value requires that state information be provided as well. Unfortunately, there is not a property in the Control Class for state information.

In many cases, the built in Windows Forms support is sufficient and therefore there is no need to specifically provide state information.

If you do need to provide state information, it will take a bit more effort. In this case, you will need to use the AccessibleObject Class and the Control.CreateAccessibilityInstance Method.

Using the Accessible* Properties of the Control Class

The following code demonstrates the use of the Control.AccessibleDescription Property and the Control.AccessibleName Property of the Control Class.

In this case, the checkbox object provides the state. However, since an image is used instead of text, it does not provide the name. Therefore the Control.AccessibleDescription Property and the Control.AccessibleName Property of the Control Class are used. In addition, these properties suffice to meet WCAG Success Criterion 4.1.2: Name, Role, Value.

References

Using Direct Annotation in C++

Sometimes you will encounter a situation in which the existing accessibility support for an user interface element is almost good enough and you need to just make small changes to the existing support. For example, perhaps you just need to override the Name or Role properties. In these cases, fully implementing the IAccessible interface as described in Implementing a Microsoft Active Accessibility (MSAA) Server Using the Windows API and C++ may seem like a great deal of effort to achieve these improvements.

Fortunately, starting with Windows 7 there is an easier alternative, the Direct Annotation feature of the Dynamic Annotation API. The Dynamic Annotation API is extension to Microsoft Active Accessibility that makes it possible to customize existing IAccessible support without using subclassing or wrapping techniques. Direct Annotation is one of several features provided by the Dynamic Annotation API; it is the simplest of the features provided.

Direct Annotation makes it possible to customize the following properties.

Since Name, Role, Value, and State are included in the list of properties supported by the Direct Annotation feature, this feature is sufficient to meet WCAG Success Criterion 4.1.2: Name, Role, Value.

Implementation Details

The first step to using the Direct Annotation feature of the Dynamic Annotation API is to create an [IAccPropServices][] object using either the CoCreateInstance function or CoCreateInstanceEx function. Then you can use either the IAccPropServices::SetHwndProp method or the IAccPropServices::SetHwndPropStr method.

The following sample from Using Direct Annotation demonstrates the technique.



More complete examples can be found in the following locations.

Note that using the IAccPropServices::SetHwndProp method or the IAccPropServices::SetHwndPropStr method will not send WinEvents. It is your responsibility to send appropriate events by calling the NotifyWinEvent function after the IAccPropServices::SetHwndProp method or the IAccPropServices::SetHwndPropStr method has been called.

For example, if you use IAccPropServices::SetHwndPropStr method to set the Name property of an element, send an EVENT_OBJECT_NAMECHANGE event for that object after SetHwndPropStr returns.

The CWndWithCustomizedAccessibleInfo class and DirectAnnotation class both make the necessary calls to the NotifyWinEvent function for you.

Implementing a Microsoft Active Accessibility (MSAA) Server Using the Windows API and C++

The oldest and simplest of the Accessibility APIs used in Microsoft Windows is Microsoft Active Accessibility or MSAA. This article provides a brief introduction on how to implement a MSAA Server using the Windows API and the C++ programming language.

The IAccessible interface

The heart of MSAA is the IAccessible interface. This interface exposes methods and properties that allow an accessibility server to make a user interface element and its children accessible to accessibility client applications. The methods and properties of the IAccessible interface allow a Windows API application to meet WCAG Success Criterion 4.1.2: Name, Role, Value, which requires that an accessibility client be able to programmatically determine the Name, Role, Value, and States of all user interface components (including but not limited to: form elements, links and components generated by scripts).

The following table provides information the methods of the IAccessible interface that are used to expose each of these properties.

Property Method
Name IAccessible::get_accName
Role IAccessible::get_accRole
State IAccessible::get_accState
Value IAccessible::get_accValue

See the IAccessible interface page for a complete list of the members of the interface and a detailed description of each method. The Content of Descriptive Properties page provides information on the expected value of these properties.

The Name, Role, and State properties are required for all user interface components that can gain focus. The Value property may be required for some user interface components but not for others. More information on which members of the IAccessible interface should be implemented for a given user interface component can be found in the Choosing Which Properties to Support page.

How an accessibility client obtains an IAccessible object

An accessibility client use one of the following functions to obtain an IAccessible object.

See the Getting an Accessible Object Interface Pointer page for more information on these functions.

What happens when an accessibility client requests an IAccessible object?

When an accessibility client requests an IAccessible object using the AccessibleObjectFromEvent, AccessibleObjectFromPoint, and AccessibleObjectFromWindow functions Microsoft Active Accessibility sends the WM_GETOBJECT message to the appropriate window procedure within the appropriate server application with the lParam parameter set to OBJID_CLIENT. Your Microsoft Active Accessibility (MSAA) server needs to handle this message.

Handling the WM_GETOBJECT Message

When your Microsoft Active Accessibility (MSAA) Server receives the WM_GETOBJECT message it should return the value obtained by passing the IAccessible interface of the object to the LresultFromObject function as follows.



The above code is from the Windows API Accessibility Server sample application.

For more information on handling the WM_GETOBJECT message see the following.

Events

Implementing the IAccessible interface is just one part of the puzzle. You also need to notify fire event notifications. This is done using the NotifyWinEvent function. See Event Constants, System-Level and Object-Level Events, and What Are WinEvents? for more information.

Additional Resources

Additional information can be found in the following locations.

Donnie Trumplestiltskin Does Not Seem to Know Who Owns Forests in California

Donnie Trumplestiltskin Does Not Seem to Know Who Owns Forests in California

Ben Key

January 09, 2019

Trump Troll :: The Troll We Let into Washington
Trump Troll :: The Troll We Let into Washington

Donnie Trumplestiltskin reportedly has said he has ordered the Federal Emergency Management Agency (FEMA) to withhold funding for California unless the state improves its forest management to prevent wildfires. For more on this see Trump tells FEMA not to send more money to California for forest fires.

I do not know, or care, if there is any truth to his claims that forest mismanagement is the cause of the forest fires.

For the sake of argument, lets assume that forest mismanagement is in fact the cause of the forest fires and consider who is to blame.

According to California Forests, the following individuals own the approximately 33 million acres of forest land in California.

Percentage Owner
57% Federal agencies (including the USDA Forest Service and USDI Bureau of Land Management and National Park Service).
40% Families, Native American tribes, or companies.
3% State and local agencies including CalFire, local open space, park and water districts and land trusts.

In other words, the Federal Government owns most of the forest land in California! Therefore, if the forest fires are the result of mismanagement, it is the Federal Government’s fault. So, Donnie Trumplestiltskin is threatening to punish a state for the actions of the Federal Government!

All hail Donald Trump; a.k.a. Donald Drumpf, a.k.a. Lord Dampnut, a.k.a. Dumbnut, a.k.a. Donnie Trumpelstiltskin, a.k.a. Donald tRUMP; our most, or perhaps least, honored (not my) POTUS and our great Bloviator in Chief!

Trump Troll Image Information

Source
Dave Phillips on Flickr
License
CC BY-ND 2.0

Our Moral Obligation to Grant Asylum to Refugees from Central America

Ben Key:

November 28, 2018

Recently, the Trump administration has done everything it could to make it more difficult to seek asylum in The United States of America.

These actions are morally reprehensible.

To begin with, these people are fleeing truly terrible conditions that include violence, organized crime, extremely low incomes, and truly unbearable living conditions. They did not decide to travel over 2,000 miles on a whim. They are fleeing clear and present danger.

These descriptions of what the refugees are fleeing should be enough to convince anyone with an ounce of compassion to welcome these refugees from Central America with open arms and grant them asylum in The United States of America, especially if they claim to be Christian.

When a foreigner resides among you in your land, do not mistreat them. The foreigner residing among you must be treated as your native-born. Love them as yourself, for you were foreigners in Egypt. (Leviticus 19:33-34)

Compassion, empathy, and common decency are not the only reasons why we should be welcoming these refugees instead of turning them away. There are numerous sources that provide overwhelming evidence that these refugees are fleeing conditions that were created by actions directly taken by the government of The United States of America over the past 100 years.

We helped create the issues that caused the refugee crisis. We have a moral obligation to provide those who are fleeing the conditions we created a place of safety where they can live in peace. We have a moral responsibility to make right our wrongs!

Do not be deceived: God cannot be mocked. A man reaps what he sows. (Galatians 6:7)